当前位置:澳门贵宾厅 > 澳门贵宾厅 > 这个类库中有个loadDeps方法,会将所有的js代码打包为一个整体
这个类库中有个loadDeps方法,会将所有的js代码打包为一个整体
2020-02-01

CopyWebpackPlugin会把 src/deps/ 中的文件复制到 dist/ 目录中,这时候dist/就会变成:

分模块打包之后在 dist目录下是这样的, 这样就把一个大的 js文件分为一个个小的js文件了,按需去下载,其他的使用方法和import的效果一样

// my-lib.jsclass MyLib { loadDeps() { return new Promise((resolve, reject) = { if (global.TextDecoder === undefined) { return Promise.all([ import('./deps/text-encoding'), import('./deps/other-dep.js'), import('./deps/another-dep.js'), ]).then(resolve).catch(reject); } else { resolve(); } }); } initialize() { this.decoder = new TextDecoder(); // ... }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

// my-lib.jsclass MyLib { constructor(options) { this.onLoadDeps = options.onLoadDeps || null; } loadDeps() { return new Promise((resolve, reject) = { if (global.TextDecoder === undefined) { if (this.onLoadDeps) { this.onLoadDeps().then(resolve).catch(reject); } else { Promise.all([ import('./deps/text-encoding'), import('./deps/other-dep.js'), import('./deps/another-dep.js'), ]).then(resolve).catch(reject); } } else { resolve(); } }); }} // app.jsimport MyLib from 'my-lib';class App { constructor() { this.myLib = new MyLib({ onLoadDeps: () = Promise.all([ import('my-lib/dist/text-encoding'), import('my-lib/dist/other-dep.js'), import('my-lib/dist/another-dep.js'), ]); }); }}

1、require.ensure()

对应用层来说,为了一个库而改服务器配置就显得太麻烦了。

module.exports={ entry:'./js/entry.js', output:{ path:path.resolve, filename:'js/a.bundle.js', publicPath:"./", chunkFilename:'js/[name].js' }
const CopyWebpackPlugin = require('copy-webpack-plugin'); module.exports = { output: { ... }, plugins: [ new CopyWebpackPlugin([{ from: 'src/deps/', to: '.' }]) ]}

chunk名称 chunkName

想要webpack不处理import(),那么就不能让webpack去解析含有import()的文件,即需要把含有加载依赖的部分分离到另一个文件中。

根据 chunkame的不同, 上面的四个组件, 将会被分成3个块打包,最终打包之后与组件相关的js文件会分为3个 (除了app.js,manifest.js, vendor.js)

// my-lib.jsclass MyLib { constructor(options) { this.importPrefix = options.importPrefix || './deps'; } loadDeps() { return new Promise((resolve, reject) = { if (global.TextDecoder === undefined) { return Promise.all([ import(this.importPrefix + '/text-encoding'), import(this.importPrefix + '/other-dep.js'), import(this.importPrefix + '/another-dep.js'), ]).then(resolve).catch(reject); } else { resolve(); } }); }} // app.jsimport MyLib from 'my-lib';class App { constructor() { this.myLib = new MyLib({ importPrefix: 'my-lib/dist' }); }}

b.js 被打包进 0.bundle.js.

当我们发布到npm仓库之前,我们会先用Webpack构建项目,这时候webpack就会分析文件中的依赖路径,把依赖文件生成到output.path中,同时import()方法就已经变成webpack内部的方法了,依赖的路径也变成output.publicPath相关的了。假设我们的webpack配置是这样的:

、单独打包成自己写的名字配置

然后修改webpack配置:

const Province = r => require.ensure => r(require('@/components/Province.vue')), 'chunkname1')const Segment = r => require.ensure => r(require('@/components/Segment.vue')), 'chunkname2')const Loading = r => require.ensure => r(require('@/components/Loading.vue')), 'chunkname3')const User = r => require.ensure => r(require('@/components/User.vue')), 'chunkname3')
// dist/index.js/******/ ([/* 0 *//***/ (function(module, exports) { module.exports = { onLoadDeps: function onLoadDeps() { return Promise.all([import('my-lib/dist/text-encoding'), import('my-lib/dist/other-dep.js'), import('my-lib/dist/another-dep.js')]); }}; /***/ }),/* 1 *//***/ (function(module, __webpack_exports__, __webpack_require__) { // ... var MyLib =/*#__PURE__*/function () { function MyLib() {} var _proto = MyLib.prototype; _proto.loadDeps = function loadDeps() { var _this = this; return new Promise(function (resolve, reject) { if (global.TextDecoder === undefined) { _runtime__WEBPACK_IMPORTED_MODULE_0___default.a.onLoadDeps().then(resolve).catch(reject); } else { resolve(); } }); }; _proto.initialize = function initialize() { this.decoder = new TextDecoder(); // ... }; return MyLib;}(); // ...

所以我们需要分模块打包,把我们想要组合在一起的组件打包到一个 chunk块中去,分模块打包需要下面这样使用 webpack的 require.ensure,并且在最后加入一个 chunk名,相同 chunk名字的模块将会打包到一起。

先来准备一下 dist/ 的目录结构,修改webpack的配置:

webpack中利用require.ensure()实现按需加载

手机版澳门贵宾厅,注意,本文是写给类库作者看的,如果读者写的是应用,那就没有必要往下看了。

entry.js 和 a.js 被打包进 bundle.js.

这个方案稍微复杂一点点。

2、require.ensure() 的坑点

然后输出了这些文件:

使用 vue-cli构建的项目,在 默认情况下 ,执行 npm run build 会将所有的js代码打包为一个整体,

如果应用层引用了这个类库,那么webpack打包应用的时候就会处理类库中的import(),这样就和应用层平时的动态加载一样了,上面的问题也就解决了。

需要配置chunkFilename,和publicPath。publicPath是按需加载单独打包出来的chunk是以publicPath会基准来存放的,chunkFilename:[name].js这样才会最终生成正确的路径和名字

当然,我们还可以修改服务端配置,把/1.js和**/1.js都指向/path/to/project/node_modules/my-lib/dist/1.js。

\ file structure | js --| | |-- entry.js | |-- a.js | |-- b.js webpack.config.js | dist

\ entry.jsrequire;require.ensure{ require;

\ a.jsconsole.log;

\ b.jsconsole.log;

\ webpack.config.jsvar path = require;module.exports = function { return { entry: './js/entry.js', output: { filename: 'bundle.js', path: path.resolve } }}
// my-lib.jsimport RUNTIME from './runtime'; class MyLib { loadDeps() { return new Promise((resolve, reject) = { if (global.TextDecoder === undefined) { RUNTIME.onLoadDeps().then(resolve).catch(reject); } else { resolve(); } }); }}
require.ensure(dependencies: String[], callback: function, chunkName: String)

对于这个解决方案,其实还有一个变种,相对来说更加方便:

通过执行这个项目的 webpack 构建,我们发现 webpack 创建了2个新的文件束, bundle.js 和 0.bundle.js。

这时候可以像方案一那样,用import(importPrefix+’/text-encoding’)的方式来解决,也可以利用NormalModuleReplacementPlugin来解决。

执行 npm run build 会打包为一个整体 app.[contenthash].js ,这个文件是非常大,可能几兆或者几十兆,加载会很慢

不足之处是如果有多个项目都引用了这个类库的话,那么当类库添加了新的依赖时,所有引用了这个类库的项目都要改动源码。这会是一个比较繁琐的事情。

这是一个字符串数组,通过这个参数,在所有的回调函数的代码被执行前,我们可以将所有需要用到的模块进行声明。

那么当应用层调用app.myLib.loadDeps()的时候会加载依赖的路径会是怎样的呢?猜对了,浏览器会尝试加载这些路径:

打包位置是 dist/static/js/app.[contenthash].js

这个方案虽然有些繁琐,但最大的优点是可以把依赖管理都交给类库自己处理,不需要应用层干预。就算类库日后改变打包位置(不再是dist/)也无需让应用层知道。

require.ensure{ require;

这个类库中有个loadDeps方法,会根据运行环境检测TextDecoder是否存在,如果不存在就会去加载依赖,这些依赖是在本地目录中。

所以router/index.js 修改为懒加载组件:

// app.jsimport MyLib from 'my-lib';class App { constructor() { this.myLib = new MyLib(); }} const app = new App();app.myLib.loadDeps().then(() = { app.myLib.initialize(); console.log(app.myLib.decoder);});

vue-cli是由vue官方发布的快速构建vue单页面的脚手架。

当我们把类库发布到npm之后,我们就会这么使用它:

webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。这个新的 chunk 会被 webpack 通过 jsonp 来按需加载。

下一步就是让webpack不解析import()了,这里有两种做法:

以上代码保证了拆分点被创建,而且 a.js 被 webpack 分开打包。

/1.js/2.js/3.js

回调 callback

方案一:由应用层处理

require.ensure(['./a.js'], function { require;
dist├── 1.js├── 2.js├── 3.js├── text-encoding.js├── other-dep.js├── another-dep.js└── index.js

想去执行 a.js,我们需要异步地引用它,如 require,让它的 JavaScritp 被执行。

这个插件可以改变重定向资源,上面的配置是把my-lib/dist/*里面的资源都重定向到../src/deps。

上面代码, a.js 和 b.js 都被打包到一起,而且从主文件束中拆分出来。但只有 b.js 的内容被执行。a.js 的内容仅仅是可被使用,但并没有被输出。

// webpack.dev.jsmodule.exports = { // ... plugins: [ new webpack.NormalModuleReplacementPlugin(/my-lib/dist/(.*)/, function (resource) { resource.request = resource.request.replace(/my-lib/dist/, '../src/deps') }), ]}

当所有的依赖都加载完成后,webpack会执行这个回调函数。require 对象的一个实现会作为一个参数传递给这个回调函数。因此,我们可以进一步 require() 依赖和其它模块提供下一步的执行。

注意:这个变种方案有可能会出现 Critical dependency: the request of a dependency is an expression 的报错。

依赖 dependencies

更多详细的用法,可以参考下官方文档NormalModuleReplacementPlugin。

import Hello from '@/components/Hello'import Province from '@/components/Province'import Segment from '@/components/Segment'import User from '@/components/User'import Loading from '@/components/Loading'

对一个类库来说,它应该管理好自己的依赖,不应该让应用层甚至是服务器端来配合。

chunkName 是提供给这个特定的 require.ensure() 的 chunk 的名称。通过提供 require.ensure() 不同执行点相同的名称,我们可以保证所有的依赖都会一起放进相同的 文件束。

// runtime.jsmodule.exports = { onLoadDeps: function() { return Promise.all([ import('my-lib/dist/text-encoding'), import('my-lib/dist/other-dep.js'), import('my-lib/dist/another-dep.js'), ]); }}

router/index.js 路由相关信息,该路由文件引入了多个 .vue组件

时间: 2019-03-02阅读: 471标签: 打包前言

我们需要解决这个路径问题,既要保证结果正确,又要方便开发。很明显,这个问题是因为webpack打包的时候处理了import()导致的,如果我们不在编译时处理,而是运行时处理,这不就可以达到目的了吗?

这个方案很容易实现,只需要让应用层来调用import()就可以了。

在编写库的时候,我们有时候会希望按需加载某些依赖,例如如果代码的运行环境不支持某些功能的话,就加载相关的Polyfill。webpack作为当前最流行的打包工具,早已支持动态加载的功能了。本文将讨论一种用webpack打包含动态加载的类库的方法。

方案二:由类库处理

注意:这个插件最好只用在开发环境中。

示例类库

解决方案

这样,我们的类库无论在什么环境都能使用到TextDecoder了。但,真的会这么顺利吗?

// webpack.config.jsmodule.exports = { output: { filename: 'index.js', chunkFilename: '[name].js', path: 'dist/', publicPath: '/', libraryTarget: 'umd' }, // ...};

注意:因为 webpack 不会解析这个文件,loader 就不会处理这个文件,所以这个文件里面最好使用 Node.js 原生支持的语法。

问题

但是结果呢?当然是404了。因为网站的根目录没有这些文件呀,除非你把这些文件复制到网站根目录。同样道理,如果publicPath是相对路径的话(假设是”),那么请求依赖的路径就会相对于当前的URL了,即如果当前URL是/topics/:uid,那请求的路径就会是/topics/:uid/1.js。除非当前目录下有这些依赖,不然结果还是404。

最后剩下一个问题,那就是在开发环境下,我们也需要测试runtime.js,但这时候它是import(‘my-lib/dist/xxx’)的,这个肯定会报Error:Cannotfindmodule的错误。

这种做法非常简单,而且在开发环境下也不需要任何处理就能正常运行了。

// webpack outputBuilt at: 02/19/2019 5:08:41 PM Asset Size Chunks Chunk Names 1.js 79 bytes 1 [emitted] 2.js 79 bytes 2 [emitted] 3.js 79 bytes 3 [emitted]index.js 144 KiB 0 [emitted] mainEntrypoint main = index.js

作者:scarletskyscarletsky.github.io/2019/02/19/webpack-bundling-libraries-with-dynamic-imports/

这样,webpack在处理my-lib.js的时候会把runtime.js加载进来,但不会去解析它。所以会得到以下的结果:

module.exports = { output: { ... }, module: { noParse: /src/runtime/, }, plugins: [ ... ] }