webpack2--4多页面支持& 公共组件单独打包

  1. 本篇主要介绍:如何自动构建入口文件,并生成对应的output;公共js库如何单独打包。
  2. 多入口文件,自动扫描入口。同时支持SPA和多页面型的项目.
  3. 公共js库如何单独打包。

基础目录

以下示例基于上一篇进行改进,上一篇项目源码

.
├── 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.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"

var glob = require('glob')
//entries函数
var entries = function() {
	var jsDir = path.resolve(srcDir, 'js')
	//执行同步全局搜索,返回{array<string>}文件名数组对象
   	 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")
$("<div>这是jquery生成的多页面示例</div>").appendTo("body")
  1. 新增pageA.html,也顺便修改index.html对于js文件名的更改
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script src="../dist/index.js"></script>
</body>
</html>
  1. 执行webpack,启动webpack-dev-server
$ webpack
$ webpack-dev-server

在这里插入图片描述

公共库单独打包

之前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

{
	name:string,//公共模块的名称
	names:string|string[],//公共模块名称
	minChunks :number|Infinity|function(module,count) - boolean,//为number表示需要被多少个entries依赖才会被打包到公共代码库;为Infinity 仅仅创建公共组件块,不会把任何modules打包进去。并且提供function,以便于自定义逻辑。
	chunks:string[],//只对该chunks中的代码进行提取
	children:boolean,//为true时候,那么公共组件的所有子依赖都将被选择进来
	async:boolean|string,//如果为true,将创建一个 option.name的子chunks(options.chunks的同级chunks) 异步common chunk
	minSize:number//所有公共module的size 要大于number,才会创建common chunk
}

列子

  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)
})
  1. 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)
})

修改webpack.config.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
        })
    ]
}

修改index.html和pageA.html,增加对vendor.js的引用

<script src="../dist/vendor.js"></script>
<script src="../dist/index.js"></script>
<script src="../dist/pageA.js"></script>

执行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 放在前面。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值