webpack
常用loader
-
css-loader 处理css结尾的文件
-
style-loader 将样式内嵌在htmlheader内
-
file-loader 以外链方式加载样式
-
sass-loader
-
less-loader
-
postcss-loader
注:loader处理从右到左
常用plugin
- html-webpack-plugin 自动生成html文件
- clean-webpack-plugin 自动清除目录内的文件
开发
-
source-map devtool: 'inline-source-map'
-
开发工具 webpack watch mode
"scripts":{ "watch": "webpack --config webpack.config.js --watch" }webpack-dev-server(使用最多)
// webpack.config.js module.exports = { ... devServer:{ contentBase: path.resolve(__dirname,'dist') } } // package.json { "scripts":{ "dev": "webpack-dev-server --open" } }webpack-dev-middleware
webpack-dev-middleware是一个容器,它可以把webpack处理后的文件发送到一个服务器,webpack-dev-server在内部使用了它,也可以单独拿出来
热模块替换(HMR)
它允许在运行时更新各种模块,而无需进行完全刷新
-
启用
devServer:{ hot: true }
tree-shaking
移除上下文中的未引用代码,通过package.json的“sideEffects”属性作为标记,像compiler提供提示,表明项目中的哪些文件是pure(纯es2015模块),由此可以安全地删除文件中使用的部分
// package.json
{
"sideEffects": false
}
// 任何导入的文件都会受到treeShaking影响,这意味着如果在项目中使用类似css-loader并导入css文件,则需要将其添加到sideEffect列表中,以避免在生产模式中无意中将它删除
{
"sideEffects":[
"./src/project/project.js",
"*.js"
]
}
压缩输出
使用webpack编译标记,来启用uglifyjs压缩插件
module.exports = {
mode: 'production'
}
生产环境构建
// webpack.common.js
{
entry:{},
plugins:[
new CleanWebpackPlugin(),
new HtmlWebpackPlugin()
],
output:{
filename:'[name].bundle.js',
path:path.resolve(__dirname,'dist')
}
}
// webpack.dev.js
{
devTool: 'inline-source-map'
//避免在生产中使用* `inline-***` *和* `eval-***`*,因为它们可以增加 bundle 大小,并降低整体性能。*
devServer:{
contentBase: path.resolve(__dirname,'dist'),
hot: true
}
}
// webpack.prod.js
const merge = require('webpack-merge')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const common = require('./webpack.common.js')
module.exports = merge(common,{
plugins:[
new UglifyJSPlugin()
]
})
// 指定环境
const webpack = require('webpack');
module.exports = {
plugins:[
new webpack.DefinePlugin({
'process.env.NODE_ENV':JSON.stringify('production')
})
]
}
// split css
代码分离
CommonsChunkPlugin
CommonsChunkPlugin已经从webpack v4 legato中移除,如何处理chunk,请使用SplitChunksPlugin
动态导入
function getComponent(){
return import(/* webpackChunkName: 'lodash' */ 'lodash').then(_ =>{
const el = document.createElement('div')
el.innerHTML = _.join(['hello'])
return el
}).catch(err => 'an error')
}
vue 懒加载
- lazy load in components
Vue.Component('AsynCmp',() => import("./AsyncCmp"))
new Vue({
components:{
AsyncCmp: () => import('./asyncCmp')
}
})
- lazy load in VueRouter
const login = () => import("./login")
new VueRouter({
routes:[{
path: '/login',
component: login
}]
})
- lazy load in Vuex module
const store = new Vuex.Store()
import('./store/login').then(loginModule => {
store.registerModule('login', loginModule)
})
缓存
-
contenthash
资源内容发生变化时,contenthash也会发生变化
-
第三方库提取到单独vendor
可使用
optimization.runtimeChunk选项将 runtime 代码拆分为一个单独的 chunk。将其设置为single来为所有 chunk 创建一个 runtime bundle
module.exports = {
optimization:{
runtimeChunk: 'single',
splitChunks:{
cacheGroups:{
vendor:{
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
}
-
模块标识符
添加print.js打包后,文件的 hash 都变化了。这是因为每个
module.id会默认地基于解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变。因此,简要概括:mainbundle 会随着自身的新增内容的修改,而发生变化。vendorbundle 会随着自身的module.id的变化,而发生变化。manifestbundle 会因为现在包含一个新模块的引用,而发生变化。
vendor的hash变化是要修复的
const webpack = require('webpack')
module.exports = {
plugins:[
new webpack.HashModuleIdsPlugin()
]
}
创建library
// 初始化
npm init -y
npm i -S webpack lodash
// src/index.js
import _ from 'lodash'
import numRef from './ref.json'
export function numToWord(num){....}
export function wordToNum(word){...}
// library调用规范 es2015
import * as webpackNumbers from 'webpack-numbers'
webpack.wordToNum('two')
// 外部化lodash
module.exports = {
entry:'',
output:{},
externals:{
lodash:{
commonjs: 'lodash',
root: '_'
}
}
}
shim预置全局变量
使用ProvidePlugin后,能够在webpack编译的每个模块中,通过访问一个变量来获取一个package,webpack看到模块中用到这个变量,它将在最终bundle中引入给定package
// src/index.js
function component(){
const element = document.createElement('div')
element.innerHTML = _.join(['a','b'])
return element
}
document.body.appendChild(component())
// webpack.config.js
const webpack = require('webpack')
module.exports = {
plugins:[
new webpack.ProvidePlguin({
_: 'lodash'
})
//或者使用数组形式
new webpack.providePlugin({
join:['lodash','join']
// 只要调用join方法就会使用lodash内的方法,这样就能很好的与tree shaking配合,将lodash libary中的其余没有用到的导出去除
})
]
}
TypeScript
- 基础配置
npm install -D typescript ts-loader
项目中添加tsconfig.json
环境变量
// webpack.config.js
module.exports = env => {
console.log(env.NODE_ENV)
}
构建性能
对最少数量的必要模块使用 loader。不应该如下:
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
}
};
而是使用 include 字段仅将 loader 应用在实际需要将其转换的模块所处路径:
module.exports = {
//...
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
loader: 'babel-loader'
}
]
}
};