Webpack学习笔记
webpack - 项目优化
webpack实现原理
webpack - loader
webpack - plugin
webpack - 项目优化2
安装
npm install --save-dev webpack
npm install --save-dev webpack-cli
// package.json
"scripts": {
"start": "webpack-dev-server",
"build": "webpack --config webpack.config.js"
}
配置出入口
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js', // 同步代码
chunkFilename: '[name].min.js', // 异步代码
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://xxx.xxx.com' // 所有资源使用域名
}
// loader们
module: {
rules: [
// 配上babel
{ test: /\.js$/, use: {
loader: 'babel-loader',
options: { presets: ['@babel/preset-env'] }
} }
]
},
// 插件
plugins: []
};
// ./src/index.js
let mylib = require('./lib')
console.log(888, mylib())
// ./src/lib.js
module.exports = () => 'i from lib'
运行npm run start
成功打包出 bundle.js 和 index.html
暴露变量的三种方式
-
插件: webpack.ProvidePlugin
在 index.js 中不用引用lib文件,就可以直接引用。
new webpack.ProvidePlugin({
'mylib': path.resolve(__dirname, 'src/lib.js')
})
// 打包后代码:
function(e,t,n){(function(e){console.log(888,e())}).call(this,n(1))},function(e,t){e.exports=function(){return"i from lib"}}
-
loader: expose-loader
在项目中任一位置引用一次,就会绑定到window对象上
{ test: path.resolve(__dirname, 'src/lib.js'), use: {
loader: 'expose-loader',
options: 'lib'
} }
-
插件:add-asset-html-cdn-webpack-plugin
相当于在html中添加了script标签引入的。不会被打包
new addAssetHtmlCdnWebpackPlugin(true, {
'jquery': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js'
})
-
配置外部对象:externals
需在项目中任一位置引用一次。不会被打包
externals: {
'jquery': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.js'
},
// ./src/index.js
// let mylib = require('./lib')
// console.log(888, mylib())
import $ from 'jquery';
console.log( $('body') )
Tree-shaking(仅对es6模块有效)
先修改两个js文件以方便实验
// ./src/index.js
import {fn1} from './lib'
console.log(777, fn1())
// ./src/lib.js
export const fn1 = () => 'i am fn1, from lib'
export const fn2 = () => 'i am fn2, from lib'
webpack中Tree-shaking自动生效,但仅在生产环境(mode: 'production'
)下。基于uglifyjs。
在开发(development)中,可以标识没有使用的模块
mode: 'development',
optimization: {
usedExports: true
},
打包出来后:
/***/ "./src/lib.js":
/*!********************!*\
!*** ./src/lib.js ***!
\********************/
/*! exports provided: fn1, fn2 */
/*! exports used: fn1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
...
如果模块中涉及到了自执行(比如在lib.js中引用了其它模块,未调用,但被引用的模块自调用过),会shaking不掉它(
副作用
)。如果想消除副作用,可以在package.json中添加"sideEffects":false
"sideEffects":false
会导致css的import被shaking掉。需要"sideEffects":["*.css"]
指明使用哪些副作用
scope-hosting 作用域提升
把变量、方法进行压缩提取,以减少变量数量
热更新
webpack自代硬更新,即有修改后刷新页面
css-loader内部自动支持热更新
js热更新:
// webpack.config.js
devServer: { hot: true },
plugins: [
new webpack.HotModuleReplacementPlugin()
]
// ./src/index.js
import {fn1} from './lib'
let p = document.createElement('p')
p.innerHTML = fn1()
p.onclick = function () {
p.innerHTML += '欲哭无泪'
}
document.body.appendChild(p)
// 热更新
if (module.hot) {
module.hot.accept(['./lib'], () => {
console.log(888, fn1())
})
}
// ./src/lib.js
export const fn1 = () => 'i am fn1, from lib'
export const fn2 = () => 'i am fn2, from lib'
运行后,点击p标签打印 777, i am fn1, from lib欲哭无泪
修改lib.js中的代码后,页面上的欲哭无泪
还在,浏览器也没有刷新,热更新成功!好不方便的说
webpack-dev-server 热更新
// webpack-dev-server配置
devServer: {
port: 7070,
contentBase: './dist'
}
可以webpack.config.js中添加如上配置,使用webpack-dev-server
命令启动调试
懒加载
原理是jsonp,用法是import().then
let p = document.createElement('p')
p.innerHTML = '懒加载'
p.onclick = function () {
// 打包出来的文件名是 lib
// import(/* webpackChunkName:"lib" */ './lib').then()
// 预请求,所有同步js加载完成后,加载lib,但并不执行
import(/* webpackPrefetch:true */ './lib').then()
// 除此之外还有:预加载 webpackPreload、 dns-prefetch 等
}
document.body.appendChild(p)
在点击后加载 1.bundle.js(取决于 chunkFilename)文件;打包后 lib.js 也会被单独打出来。此语法是es7提案,如果提示不支持此语法,可以使用此loader:
{ test: /\.js$/, use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
// 此loader
plugins: ['@bable/plugin-syntax-dynamic-import']
}
} },
忽略插件
// 在 lib.js 中添加对 moment 的引用
var moment = require('moment');
console.log(moment().format())
打包后 bundle.js 有319k
Asset Size Chunks Chunk Names
bundle.js 319 KiB 0 [emitted] [big] main
index.html 182 bytes [emitted]
忽略插件IgnorePlugin moment的语言包,位于/locale/..js
// webpack.config.js
plugins: [
new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/ })
]
Asset Size Chunks Chunk Names
bundle.js 61.2 KiB 0 [emitted] main
index.html 182 bytes [emitted]
打包后 bundle.js 只有61k了。但语言包相关功能就用不了了,想使用可以再次单独引用某个语言文件,或者使用另一个插件ContextReplacementPlugin,仅打包中文语言包(打出来是63k)
// webpack.config.js
plugins: [
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/)
]
dllplugin
动态链接库插件:把代码打包好放在那里,构建时不再build他们,以节省调试时间。
// 添加 webpack.dll.js
module.exports = {
mode: 'development',
entry: ['./src/md5.js'],
output: {
library: 'mylibname', // 插件名称 => 外暴变量
libraryTarget: 'commonjs2', // 类库打包方式
filename: 'mylibname.js'
},
plugins: [
// 生成'./src/md5.js'与打好的库的映射文件
new webpack.DllPlugin({
name: 'mylibname',
path: path.resolve(__dirname, 'dist/setyourself.json')
})
]
};
// 在 webpack.config.js 中添加
plugins: [
// 加载库的映射文件
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist/setyourself.json')
}),
// 加载打包好库
new addAssetHtmlPlugin({filepath: './dist/mylibname.js'}),
]
其中 libraryTarget 支持以下方式:
"var" | "assign" | "this" | "window" | "self" | "global" | "commonjs" | "commonjs2" | "commonjs-module" | "amd" | "amd-require" | "umd" | "umd2" | "jsonp" | "system"
其它
- include/exclude
- splitChunks 抽离第三方模块
- commonChunkPlugin 快速拆分多个包
网友评论