webpack
定义:webpack 是一个模块打包器(可以打包各种模块,包括css,jpg等)。
使用webpack的价值:如果不使用webpack,项目不方便使用ESmodule的语法引用js,如果用传统方式script来引用js,这样使得每个模块都需要一个script标签,而且引用模块的代码跟使用模块的代码没有写在一起,不便于维护等。
最简单的打包例子:
npm init 初始化npm包(可以加上-y,代表yes)
npm install webpack-cli -D 安装webpack-cli(安装后可以开始使用webpack编译了,即可在命令行使用webpack命令)
npx webpack 文件路径 用webpack打包单个js文件
webpack -v 查看全局webpack的版本
npx webpack -v 查看当前环境webpack的版本
webpack可以识别任何方式导入导出模块的语法:ES Modules(export default...import ...from),CommonJs(常用于node,module.exports...require),CMD,AMD
webpack配置
默认的打包配置文件webpack.config.js
npx webpack --config 文件路径 指定其它文件作为配置文件来打包
const path = require('path') module.exports = { mode: 'development', // 默认打包模式为production,打包的文件会被压缩 // entry: './index.js', // 打包的入口文件 entry: { main: './index.js', // 等同上面的写法,打包成main.js sub: './index.js' // 也可以重复打包 }, output: { filename: "bundle.js", // 打包的文件名 path: path.resolve(__dirname, 'bundle'), // 打包的路径,当前目录+bundle plublicPath: 'http://cdn.com' // 打包后的文件引用时加上次路径 } }
打包完成的信息
Hash:此次打包的唯一哈希值
Version:当前webpack版本
Time:打包耗时
Asset:打包的文件名
Size:打包的文件大小
Chunks:js文件对应的id
Chunk Names: js文件对应的名字
loader
webpack默认只能打包js模块,非js模块需要指定loader去打包
一个规则多个loader时的执行顺序,从下到上,从右到左
file-loader可以打包任何类型的模块,原理是在dist文件夹中生成同样的文件(文件名可能不一样),并返回文件路径。字体文件也可以用它打包!
url-loader类似于file-loader,但是不在dist生成新文件,而是在打包后的js里写入图片的base64数据,可以设置limit选项,大于其数值(字节)用file-loader打包,否则用url-loader打包
css-loader 把所有的css模块打包为一个css模块
(1)importLoaders:在scss文件里import的scss不会用到postcss-loader和sass-loader,使用它可以设置使用import引用css时调用css-loader前使用loader的个数
(2)modules:可以设置是否模块化打包css,可以从css文件里import
sass-loader 用于scss打包
style-loader 把css模块里的内容挂载到head标签里
postcss-loader 很多功能,比如可以在css加前缀,以便兼容各种浏览器
plugin(插件,可以在webpack运行到某个时刻的时候,帮你处理一些事情)
htmlWebpackPlugin:打包结束后自动生成一个html文件,并把打包生成的js文件引入到html中(template选项可以设置打包后html的模板)
cleanWebpackPlugin:在webpack打包前删除指定文件夹,可以传入文件夹路径的数组(比如['dist'])
SourceMap配置(用于处理源码跟打包后代码的映射,使用后可以在程序报错时方便的看到具体源码哪一行甚至那一列出现了报错)
通过devtool来配置,开发环境推荐cheap-module-eval-source-map或者cheap-module-source-map(线上调试)
source-map: 打包速度慢,会打包一个映射文件,会提示报错的行与列
inline:同样打包速度慢,但是不会打包一个映射文件,会把映射代码放到打包后的man.js,会提示报错的行与列
cheap:打包速度较快,只会提示报错的行,不会提示具体列,只提示业务代码的报错,不提示loader里的报错
module:不仅可以提示业务代码的报错,还会提示loader里的报错
eval:打包速度最开,通过eval的形式在main.js里处理映射关系,提示内容少
有关自动打包
1、npx webpack --watch 可以监听源码的改动来实现自动打包
2、使用webpack-dev-server(推荐),开启一个web服务器,不仅可以自动打包,还会自动刷新浏览器,不会生成打包的文件,而是把打包的文件放到内存中
3、使用webpack-dev-middleware开发一个自己开发的服务器,npx node server.js
热重载
配置热重载:
devServer的hot和hotOnly都设为true并使用HotModuleReplacementPlugin插件
热重载会重新执行css代码(css-loader已实现下面功能),但不会重新执行js代码,如果需要,可以这么写(但vue-loader自带这个功能)
if (module.hot) { module.hot.accept('监听的js模块路径', js模块修改后执行的函数) }
babel配置
可以参考babel官方文档https://www.babeljs.cn,在设置里有详细的使用方法
1、安装babel-loader和@babel/core(babel核心代码)
2、在webpack.config.js添加使用babel-loader的规则
3、创建一个babel.config.json配置并启用一些预设(可以直接使用env预设,通过安装@babel/preset-env),然后再在webpack.config.js里babel-loader里加上选项presets: ['@babel/preset-env'](到这一步ES6就会打包为ES5了)
4、安装并使用@babel/polyfill(会导致打包后的文件比较大,可以配置按需引入),可是使浏览器不识别的ES6函数和方法也转为ES5(通过window.promise实现)
如果开发业务代码,以上配置即可,如果开发npm库,就需要使用@babel/plugin-transform-runtime,它可以避免polyfill污染全局环境
如果嫌babel-loader里options内容太长,可以把它放到根目录下的.babelrc
Tree Shaking(摇树,把模块当做树,把不需要的东西摇晃掉。导入且没有调用的模块在生产环境不会被打包,只支持ES Module的导人)
配置:
1、webpack.config.js加上(生产环境不需要)
optimization: { usedExports: true // 使用Tree Shaking,生产环境无需配置 }
2、在package.json文件配置sideEffects
对于部分文件不想使用Tree Shaking效果,可以通过配置sideEffects实现,false代表所有文件都会Tree Shaking
"sideEffects": ["@babel/polly-fill", "*.css"]
webpack配置文件合并 webpack-merge
代码分割,和webpack无关
1、同步代码:只需在webpack.config.js中做optimization的配置即可
optimization: { splitChunks: { chunks: 'all' // 代码分割 } }
2、异步代码(异步import):无需任何配置,会自动进行代码分割。因为使用import会提高代码的利用率,不需要在不使用的时候加载全部代码,所以是官方推荐的(默认)。
function getComponent() { return import('lodash').then(({ default: _ }) => { var element = document.createElement('div') element.innerHTML = _.join(['Dell', 'Lee'], '-') return element }) } getComponent().then(element => { document.body.appendChild(element) })
会打包出main.js和0.js,如果像把0.js改成其它名字,需要加上魔法注释
改为import(/* webpackChunkName:"lodash" */'lodash')
懒加载:通过import在特定时候加载
chunk:打包后,dist目录里的每一个js文件都是一个chunk
打包分析配置:webpack --profile --json > stats.json,还有其它配置分析插件,如:webpack-bundle-analyzer
prefetch:核心模块加载完,有空闲之后再去加载
preload:跟核心模块一起加载
css代码分割
1、使用mini-css-extract-plugin组件并引入(此插件不支持hmr,所以一般配置在线上环境比较好)
2、把style-loader替换为MiniCssExtractPlugin的loader
3、treeShaking忽略掉css:optimization.usedExports设为true,最后在package.json设置sideEffects
css代码压缩:optimize-css-assets-webpack-plugin
webpack与浏览器缓存:在output配置contenhash占位符可以让每次打包时根据content生成hash,保证代码改变后文件名变化避免读取浏览器缓存的问题
shimming垫片
场景:设置某全局变量对应的模块(比如有的jQuery模块没有在模块内引用jQuery,导致无法使用$,或者有需要把this指向window)
1、使用webpack.ProvidePlugin插件
new webpack.ProvidePlugin({ $: 'jquery' // 遇到模块里使用了$,就引入jquery模块 })
2、使用imports-loader模块
use: [
{ loader: 'imports-loader?this=>window' // 将this指向window }
]