扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
这篇文章将为大家详细讲解有关webpack中多页面/入口支持与公共组件单独打包的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
公司主营业务:成都网站设计、网站建设、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联推出河间免费做网站回馈大家。
基础结构和准备工作
以下示例基于上一篇进行改进,上一篇项目源码
目录结构说明
. ├── package.json # 项目配置 ├── src # 源码目录 │ ├── pageA.html # 入口文件a │ ├── pageB.html # 入口文件b │ ├── css/ # css资源 │ ├── img/ # 图片资源 │ ├── js # js&jsx资源 │ │ ├── pageA.js # a页面入口 │ │ ├── pageB.js # b页面入口 │ │ ├── lib/ # 没有存放在npm的第三方库或者下载存放到本地的基础库,如jQuery、Zepto、avalon │ ├── pathmap.json # 手动配置某些模块的路径,可以加快webpack的编译速度 ├── webpack.config.js # webpack配置入口
一:自动构建入口
官方多入口示例
webpack默认支持多入口,官方也有多入口的示例。配件文件webpack.config.js如下
//已简化 var path = require("path"); module.exports = { entry: { pageA: "./pageA", pageB: "./pageB" }, output: { path: path.join(__dirname, "js"), filename: "[name].bundle.js", chunkFilename: "[id].chunk.js" } }
每新增一个页面就需要在webpack.config.js的entry 中增加一个 pageC:"./pageC",页面少还好,页面一多,就有点麻烦了,而且配置文件,尽可能不改动。那么如何支持不修改配置呢?
自动构建入口函数
entry实际上是一个map对象,结构如下{filename:filepath},那么我们可以根据文件名匹配,很容易构造自动扫描器:
npm 中有一个用于文件名匹配的 glob模块,通过glob很容易遍历出src/js目录下的所有js文件:
安装glob模块
$ npm install glob --save-dev
修改webpack.config.js 配置,新增entries函数,修改entry:entries(),修改output的filename为"[name].js"
//引入glob var glob = require('glob') //entries函数 var entries= function () { var jsDir = path.resolve(srcDir, 'js') var entryFiles = glob.sync(jsDir + '/*.{js,jsx}') var map = {}; for (var i = 0; i < entryFiles.length; i++) { var filePath = entryFiles[i]; var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.')); map[filename] = filePath; } return map; } //修改入口,已经修改outp的filename module.exports = { //entry: "./src/js/index.js", entry: entries(), output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, ...... //以下省略,可以见下文详细配置
测试
1.在src/js目录中新增pageA.js
//js只有两行代码,在body中加一句话 var $ = require("jquery") $("这是jquery生成的多页面示例").appendTo("body")
2.新增pageA.html,也顺便修改原来的index.html 对于js文件名的更改
3.执行webpack,启动dev-server
$ webpack $ webpack-dev-server
OK,成功打包生成pageA.js,成功运行
二:公共库单独打包
先来分析下,上个步骤打包的日志:
index.js 依赖了avalon 和 jquery,然后打包后的index.js 有480kb
pageA.js 只用了jquery,然后打包后的js 有294kb
那么如果引用的lib库多一点,又被很多页面引用,那么lib库就会被重复打包到page.js中去,模块越多重复加载的情况越严重。
如果把公共代码提取出来作为单独的js,那么就到处可以复用,浏览器也就可以进行缓存,这时候就需要用到webpack内置插件WebPack.optimize.CommonsChunkPlugin
CommonsChunkPlugin 介绍
使用
new webpack.optimize.CommonsChunkPlugin(options)
Options
翻译得比较简单,详见官方说明:
options.name or options.names(string|string[]): 公共模块的名称
options.filename (string): 公开模块的文件名(生成的文件名)
options.minChunks (number|Infinity|function(module,count) - boolean): 为number表示需要被多少个entries依赖才会被打包到公共代码库;为Infinity 仅仅创建公共组件块,不会把任何modules打包进去。并且提供function,以便于自定义逻辑。
options.chunks(string[]):只对该chunks中的代码进行提取。
options.children(boolean):如果为true,那么公共组件的所有子依赖都将被选择进来
options.async(boolean|string):如果为true,将创建一个 option.name的子chunks(options.chunks的同级chunks) 异步common chunk
options.minSize(number):所有公共module的size 要大于number,才会创建common chunk
2个常用的例子,更多例子见官方说明:
1.Commons chunk for entries:针对入口文件提取公共代码
new CommonsChunkPlugin({ name: "commons", // (the commons chunk name) filename: "commons.js", // (the filename of the commons chunk) // minChunks: 3, // (Modules must be shared between 3 entries) // chunks: ["pageA", "pageB"], // (Only use these entries) })
2.Explicit vendor chunk:直接指定第三方依赖库,打包成公共组件
entry: { vendor: ["jquery", "other-lib"], app: "./entry" } new CommonsChunkPlugin({ name: "vendor", // filename: "vendor.js" // (Give the chunk a different name) minChunks: Infinity, // (with more entries, this ensures that no other module // goes into the vendor chunk) })
CommonsChunkPlugin使用
基于上篇的项目,参考上面的第二个例子,我们将jquery 和 avalon 提取出来打包成vendor.js
完整的webpack.config.js 如下:
```js var webpack = require("webpack"); var path = require("path"); var srcDir = path.resolve(process.cwd(), 'src'); var nodeModPath = path.resolve(__dirname, './node_modules'); var pathMap = require('./src/pathmap.json'); var glob = require('glob') var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; var entries= function () { var jsDir = path.resolve(srcDir, 'js') var entryFiles = glob.sync(jsDir + '/*.{js,jsx}') var map = {}; for (var i = 0; i < entryFiles.length; i++) { var filePath = entryFiles[i]; var filename = filePath.substring(filePath.lastIndexOf('\/') + 1, filePath.lastIndexOf('.')); map[filename] = filePath; } return map; } module.exports = { //entry: "./src/js/index.js", //entry: entries(), entry: Object.assign(entries(), { // 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包 'vendor': ['jquery', 'avalon'] }), output: { path: path.join(__dirname, "dist"), filename: "[name].js" }, module: { loaders: [ {test: /\.css$/, loader: 'style-loader!css-loader'} ] }, resolve: { extensions: ['.js', "", ".css"], root: [srcDir,nodeModPath], alias: pathMap, publicPath: '/' }, plugins: [ new CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity }) ] } ```
测试、验证
1.修改入口(Object.assign 是html5.js里面的....)
//entry: entries(), entry: Object.assign(entries(), { // 用到什么公共lib(例如jquery.js),就把它加进vendor去,目的是将公用库单独提取打包 'vendor': ['jquery', 'avalon'] }),
2.加入插件CommonsChunkPlugin
var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; config 中增加 plugins plugins: [ new CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity }) ]
3.修改index.html 和 pageA.html,增加对verdor.js的引用
//
4.执行webpack
$ webpack
结果分析
可以看到index.js 就只有457 bytes了,pageA.js 227bytes。vendor.js 是集成了jquery+avalon,所以有488kb。
这样vendor.js 就可以重复利用了,也方便浏览器进行缓存。
调试过程中发现
Uncaught ReferenceError: webpackJsonp is not defined
这个是因为当时把vendor.js引入 放到了page.js 后面,导致page.js执行异常,所以,请一定把vendor.js 放在前面。
生成后的index.js就很轻便了,第三方库都被打包到vendor中了,代码如下:
webpackJsonp([0],[ /* 0 */ /***/ function(module, exports, __webpack_require__) { /** * Created by sloong on 2016/6/1. */ //avalon 测试 var avalon = __webpack_require__(1); avalon.define({ $id: "avalonCtrl", name: "Hello Avalon!" }); /* //zepto 测试 require("zepto") $("这是zepto生成的").appendTo("body")*/ //jquery 测试 var $ = __webpack_require__(2) $("这是jquery生成的").appendTo("body") /***/ } ]);
页面测试均正常
关于“webpack中多页面/入口支持与公共组件单独打包的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流