webpack常见问题

Author Avatar
ibcLee 10月 23, 2017

webpack实现按需加载

webpack中通过Code Spliting实现代码的拆分,Code Spliting的具体做法就是一个分离点,在分离点中依赖的模块会被打包到一起,可以异步加载。一个分离点会产生一个打包文件。在react中通过访问当前路由去加载不同的脚本来实现按需加载。

1
2
3
4
5
6
7
8
<!-- webpack配置 -->
output: {
path: path.join(__dirname, '../dist'),
filename: '[name].js',
sourceMapFilename: '[file].map',
publicPath: '/static/',
chunkFilename: '[name].[chunkhash:5].chunk.js',
},

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- react router 配置 -->
import React from 'react';
import {
Route,
IndexRedirect,
} from 'react-router';
import rootNode from './rootNode';

const index = (location, cb) => {
require.ensure([], require => {
cb(null, require('components/Index').default);
}, 'index');
};

const routes = (
<Route path='/' component={rootNode}>
<IndexRedirect to='index' />
<Route path='index' getComponent={index} />
</Route>
);


export default routes;

多入口文件配置

为了使用多入口文件,你可以给entry传入一个对象。对象的key代表入口点名字,value代表入口点。

当使用多入口点的时候,需要重载output.filename,否责每个入口点都卸乳到同一个输出文件里面了。使用[name]来得到入口点名字。

1
2
3
4
5
6
7
8
9
10
11
{
entry: {
a: "./a",
b: "./b",
c: ["./c", "./d"]
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].entry.js"
}
}

Common Chunks

Common Chunks 插件的作用就是提取代码中的公共模块,然后将公共模块打包到一个独立的文件中去,以便在其它的入口和模块中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var webpack = require('webpack');

module.exports = {
entry:{
main1:'./main',
main2:'./main.2'
},
output:{
filename:'bundle.[name].js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('common.js', ['main1', 'main2'])
]
};

配置项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
name: string, // or
names: string[],
// 这是 common chunk 的名称。已经存在的 chunk 可以通过传入一个已存在的 chunk 名称而被选择。
// 如果一个字符串数组被传入,这相当于插件针对每个 chunk 名被多次调用
// 如果该选项被忽略,同时 `options.async` 或者 `options.children` 被设置,所有的 chunk 都会被使用,
// 否则 `options.filename` 会用于作为 chunk 名。
// When using `options.async` to create common chunks from other async chunks you must specify an entry-point
// chunk name here instead of omitting the `option.name`.

filename: string,
// common chunk 的文件名模板。可以包含与 `output.filename` 相同的占位符。
// 如果被忽略,原本的文件名不会被修改(通常是 `output.filename` 或者 `output.chunkFilename`)。
// This option is not permitted if you're using `options.async` as well, see below for more details.

minChunks: number|Infinity|function(module, count) -> boolean,
// 在传入 公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。
// 数量必须大于等于2,或者少于等于 chunks的数量
// 传入 `Infinity` 会马上生成 公共chunk,但里面没有模块。
// 你可以传入一个 `function` ,以添加定制的逻辑(默认是 chunk 的数量)

chunks: string[],
// 通过 chunk name 去选择 chunks 的来源。chunk 必须是 公共chunk 的子模块。
// 如果被忽略,所有的,所有的 入口chunk (entry chunk) 都会被选择。


children: boolean,
// 如果设置为 `true`,所有 公共chunk 的子模块都会被选择

deepChildren: boolean,
// If `true` all descendants of the commons chunk are selected

async: boolean|string,
// 如果设置为 `true`,一个异步的 公共chunk 会作为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被创建。
// 它会与 `options.chunks` 并行被加载。
// Instead of using `option.filename`, it is possible to change the name of the output file by providing
// the desired string here instead of `true`.

minSize: number,
// 在 公共chunk 被创建立之前,所有 公共模块 (common module) 的最少大小。
}

开启 babel-loader 缓存

babel编译过程很耗时,好在babel-loader提供缓存编译结果选项,在重启webpack时不需要创新编译而是复用缓存结果减少编译流程。babel-loader缓存机制默认是关闭的,打开的配置如下:

1
2
3
4
5
6
7
8
module.exports = {
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader?cacheDirectory',
}]
}
};

模块热替换

模块热替换是指在开发的过程中修改代码后不用刷新页面直接把变化的模块替换到老模块让页面呈现出最新的效果。 webpack-dev-server内置模块热替换,配置起来也很方便,下面以react应用为例,步骤如下:

  1. 在启动webpack-dev-server的时候带上–hot参数开启模块热替换,在开启–hot后针对css的变化是会自动热替换的,但是js涉及到复杂的逻辑还需要进一步配置。
  2. 配置页面入口文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import App from './app';

    function run(){
    render(<App/>,document.getElementById('app'));
    }
    run();

    // 只在开发模式下配置模块热替换
    if (process.env.NODE_ENV !== 'production') {
    module.hot.accept('./app', run);
    }

当./app发生变化或者当./app依赖的文件发生变化时会把./app编译成一个模块去替换老的,替换完毕后重新执行run函数渲染出最新的效果。