1. 代码分割(Code Splitting)
1.1 CommonsChunkPlugin
-
CommonsChunkPlugin可以进行同步代码分割。 - 代码结构
src/page/pageA.js
import './subPageA'
import './subPageB'
import lodash from 'lodash'
console.log('this is pageA')
src/page/pageB.js
import './subPageA'
import './subPageB'
import lodash from 'lodash'
console.log('this is pageB')
src/page/subPageA.js
import './module'
console.log('this is subPageA')
export default 'subPageA'
src/page/subPageB.js
import './module'
console.log('this is subPageB')
export default 'subPageB'
src/page/module.js
console.log('this is module')
export default "Module"
- 打包配置
//...
entry: {
pageA: './src/page/pageA',
pageB: './src/page/pageB',
vendor: ['lodash']
},
//...
plugins: [
//将pageA和pageB中公共代码提出
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2,
chunks: ['pageA', 'pageB']
}),
//将lodash和webpack代码分别提出
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', 'manifest'],
minChunks: Infinity
})
]
CommonsChunkPlugin可以将pageA和pageB这两个入口文件中共同引入超过minChunks次的模块拆分出来,将webpack打包代码拆分出来,将第三方依赖模块(lodash)拆分出来,但不能对单个入口文件内部多次引入的模块进行拆分。因为需要设置多个入口文件,因此CommonsChunkPlugin没有webpack4.X中的SplitChunksPlugin好用。
1.2 异步代码分割和懒加载
1.2.1 require.ensure
- 语法
require.ensure([dependencies], callback, errorCallback, chunkName)
引入模块并可以执行。
require.ensure依赖Promise。如果浏览器不支持Promise,需要添加polyfill垫片。
- 编辑打包配置文件
webpack.config.js
entry: {
pageA: './src/page/pageA'
},
output: {
filename: '[name].[hash:5].bundle.js',
path: path.resolve(__dirname, 'dist'),
chunkFilename:'[name].[hash:5].js'
},
plugins: []
入口文件只有
pageA。
需要配置chunkFilename之后,require.ensure中的第四个参数chunkName才会生效。
- 编辑代码
src/page/pageA.js
var page = 'pageA'
if(page === 'pageA') {
require.ensure([], function () {
const subPageA = require('./subPageA')
}, 'subPageA');
} else {
require.ensure([], function () {
//require('./subPageB') 如果外部也引入了subPageB,则subPageB不会被单独打包
const subPageB = require('./subPageB')
}, 'subPageB');
}
require.ensure([], function () {
const _ = require('lodash');
console.log(_.join([1,2,3], '-'))
}, 'vendor')
此时,subPageA、subPageB以及lodash会被分割打包成单独的包。
虽然subPageA、subPageB都被分割单独打包,但是subPageB不会被加载到页面中。
如果外部也引入了
require.ensure方法中通过require引入的模块,则该模块不会分割单独打包。
此时,由于subPageA和subPageB都引入了module,因此module被同时打包进了subPageA和subPageB。可通过require.include解决此问题。
1.2.2 require.include
- 语法
require.include([dependencies])
如果两个子模块都引入一个第三方模块,可在父模块中使用require.include()。这样这个第三方模块就不会同时打包进两个子模块中了。 - 编辑代码
src/page/pageA.js
require.include('./module')
var page = 'pageA'
if(page === 'pageA') {
require.ensure([], function () {
const subPageA = require('./subPageA')
}, 'subPageA');
} else {
//require('./subPageB') 如果外部也引入了subPageB,则subPageB不会被单独打包
require.ensure([], function () {
const subPageB = require('./subPageB')
}, 'subPageB');
}
require.ensure([], function () {
//会将lodash拆分打包成单独的包(除非外部已经引入了lodash)
const _ = require('lodash');
console.log(_.join([1,2,3], '-'))
}, 'vendor')
export default 'pageA'
- 此时代码打包会将
subPageA和subPageB中引入的module打包进pageA中。
1.2.3 import()
- 语法
import(
/* webpackChunkName: async-chunk-name */
/* webpackMode: lazy */
module
)
webpack推荐使用import()语法,不推荐使用require.ensure。
- 安装依赖
npm i @babel/plugin-syntax-dynamic-import -D - 编辑
babel配置
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
- 编辑代码
require.include('./module')
var page = 'pageA'
if(page === 'pageA') {
import(/* webpackChunkName: 'subPageA' */ './subPageA').then(subPageA => {
console.log(subPageA)
});
} else {
import(/* webpackChunkName: 'subPageB' */ './subPageB').then(subPageB => {
console.log(subPageB)
})
}
import(/* webpackChunkName: 'vendor' */ 'lodash').then(lodash => {
console.log(lodash.join([1,2,3], '-'))
})
export default 'pageA'
只有配置chunkFilename之后,webpackChunkName才生效。
如果多个 import()的魔法注释webpackChunkName指定同一个名字,则这多个import()模块会打包成一个bundle。
如果外部也引入了import()方法中引入的模块,则该模块不会分割单独打包。
与
require.ensure一样,由于subPageA和subPageB都引入了module,因此module被同时打包进了subPageA和subPageB。通过require.include解决此问题。
2. 加载样式
2.1 css-loader@1.X 配置项
- 安装依赖
npm install --save-dev style-loader css-loader@1.0.1
css-loader@1.X版本配置与@2.X版本配置不同。
- 编辑打包配置文件
webpack.dev.config.js
{
test: /\.css$/,
use: [
"style-loader",
{
loader: 'css-loader',
options: {
minimize: true, //压缩(失效)
modules: true, //开启modules
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}
]
}
2.2 提取CSS文件
-
extract-text-webpack-plugin文档
在
webpack4版本中,应使用mini-css-extract-plugin。
- 安装依赖
npm i extract-text-webpack-plugin -D - 编辑打包配置文件
webpack.dev.config.js
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
//...
module: {
rules: [
//...
{
test: /\.css$/,
use: ExtractTextWebpackPlugin.extract({
fallback: { loader: "style-loader"}, //应用于没有被提取的CSS使用的loader
use: [ {loader: 'css-loader'}]
})
}
]
},
plugins: [
new ExtractTextWebpackPlugin({
filename: '[name].css', //提取的css文件名
allChunks: false //异步加载的js模块中引入的css文件是否提取
}),
//...
]
}
使用模块热更新时,
css-loader已经帮我们做了module.hot.accept监听CSS文件变化的代码。使用extract-text-webpack-plugin,则CSS模块自动热更新失效,需要手写module.hot.accept监听CSS文件变化的代码。
如果ExtractTextWebpackPlugin中的filename值为css/[name].css,则会将生成的css文件放入css文件夹中。
3. Tree Shaking
- 一个简单的打包示例
src/index.js
import { add } from './math'
add(1,5)
src/math.js
export const add = (a, b) => {
console.log(a + b)
}
export const minus = (a, b) => {
console.log(a - b)
}
- 编辑打包配置文件
webpack.dev.config.js
const Webpack = require('webpack');
//...
module.exports = {
//...
plugins: [
//...
new Webpack.optimize.UglifyJsPlugin()
]
}
- 打包输出
npm run bundle
add方法被打包,minus被Tree Shaking过滤掉了。
Tree Shaking开启的关键在于JavaScript代码压缩。在webpack3.X版本中,通过UglifyJsPlugin插件进行JavaScript代码压缩。在webpack4.X版本中,mode: production生产模式默认进行JavaScript代码压缩。
4. mode
- 不支持
--mode development/production或配置文件中的{mode: development/production}定义开发模式和生产模式。
webpack3.X版本和webpack4.X版本都可以使用环境变量,且用法相同。
可参考:7. 环境变量。









网友评论