最近在学webpack,我想最好的学习方式还是要有输出才行。嗯,那就写一下博客记录一下学习的过程和收获吧。
核心概念
entry
功能:指定webpack打包的入口
单入口:entry是一个字符串
modules.exports = {
entry: './src/app.js'
}
多入口: entry是一个对象
modules.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js'
}
}
output
功能:告诉webpack如何将编译后的结果输出到磁盘 单入口
modules.exports = {
entry: './src/app.js',
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
}
}
多入口
modules.exports = {
entry: {
app: './src/app.js',
adminApp: './src/adminApp.js'
},
output: {
filename: '[name].js', // name对应的是entry的key
path: __dirname + '/dist'
}
}
loader
功能:webpack本身只支持js和json两种文件类型,通过loader把其他文件类型转换成可以添加在视图中的模块。
常见的loader
modules.exports = {
module: {
rules: [
{test: /\.txt$/, use: 'raw-loader'}
]
}
}
plugins
功能:作用于整个构建过程,可以理解为loader不能完成的事情,由plugins完成。 常用的plugins
mode
功能:用来指定当前的构建环境,webpack会根据当前的环境,开启一些配置。 参数:可以设置的值有production, development, none
常用的loader使用说明
用babel-loader配置解析js/jsx
安装babel-loader和核心依赖包
yarn add --dev babel-loader @babel/core @babel/preset-env @babel/preset-react
新建babel配置文件.babelrc 这个文件里面有两个参数,一个是plugins,一个是presents,可以理解为presets里面一个项是一系列plugins的集合,用于实现某个大功能,而plugins里面每个项都只能实现一个小功能。
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
添加babel-loader规则
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
use: 'babel-loader'
}
]
}
配置解析css
Loader的调用是链式调用,执行顺序是从右到左,所以在定义css的时候,要先写style-loader,再写css-loader,这样执行的时候,会先执行css-loader然后把执行结果传递给style-loader
yarn add --dev style-loader css-loader
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
配置解析sass
yarn add --dev node-sass sass-loader
如果上面配置了css的解析规则,那这里就只需要写一个sass-loader,把sass转换成css,然后会进入css的配置项,用css-loader继续解析。
{
test: /.scss$/,
use: [
// 如果上面没有定义css解析规则,这里要取消注释
// style-loader,
// 'css-loader',
'sass-loader'
]
}
配置解析图片字体
这里可以用url-loader和file-loader,他们的区别就是url-loader可以把图片转换成base64,而file-loader没有这个功能
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10240 // 小于10240就会被转换成base64,也可以用file-loader, file-loader不会转换成base64
}
}
]
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: 'file-loader'
}
webpack的文件监听和热更新
直接使用webpack --watch启动可以实现文件监听,但不能做到热更新。我们可以用webpack-dev-server或者webpack-dev-middleware来实现。
webpack-dev-server
WDS不把构建结果直接输出在磁盘,而是在内存中,所以速度会更快。需要配合webpack.HotModuleReplacementPlugin使用 安装依赖
yarn add --dev webpack-cli webpack-dev-server
配置
const webpack = require("webpack")
modules.exports = {
plugins: [
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: './dist',
hot: true
}
}
webpack-dev-middleware
需要配合express启动一个服务器,然后把webpack配置的内容传输给服务器。
const express = require('express')
const webpack = require('webpack')
const webpackDevMiddleware = require('webpack-dev-middleware')
const app = express()
const config = require('./webpack.config.js')
const compiler = webpack(config)
app.use(webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath
}))
app.listen(3000, function() {
console.log("app started on port 3000)
}
热更新原理:
启动阶段:
1—>2—>A—>B: 编译打包好的文件,经过bundle server,提供给浏览器,让浏览器能够以http://localhost来访问,也就是说bundle server相当于一个文件服务器。在这个阶段同时会把HMR Runtime注入到浏览器中,然后HMR Runtime跟HMR Server建立一个websocket的连接。
更新阶段
1—>2—>3—>4: 修改的文件,经过编译后,传输给HMR Server,然后HMR Server通过websocket把修改的文件传输给HMR Runtime, HMR Runtime会替换bundle.js里面的内容。
文件指纹
概念:就是我们经常看到上线之后的文件名后面加了一段hash的随机数。它用来做版本管理,例如,只更新有修改的文件。另外,对没有修改的文件,浏览器可以直接使用缓存,加速页面的加载速度。
分类:
Hash: 项目文件发生改变,整个项目的hash就会发生改变,所以无法做到一个页面的修改,
只影响它相关的打包出来的js.
Chunkhash: 一个打包出来的文件,实际上就是多个chunk构成的。Chunkhash保证了当A页面的chunk发生改变了,只修改A页面编译出来的文件的文件指纹。
Contenthash: 一个单独的文件对应的hash,只要文件内容发生改变,hash就会跟着改变。
生成:
js: 一般使用chunkhash,也就是当这个js相关的文件发生改变时,才重新生成一个js文件。
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]_[chunkhash:8].js'
},
css: 一般使用contenthash,也就是文件内容发生改变就重新生成一个css文件。如果只使用style-loader,css是作为一个style的标签,插入到html元素中,这个时候是没有独立的css文件的,所以需要配合使用MiniCssExtractPlugin。
module: {
rules: [
{
test: /.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
图片/文字: 一般使用hash,这里的hash就是contenthash,直接在loader那里配置
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name]_[hash:8][ext]'
}
}
]
}
代码压缩
js压缩:使用uglifyjs-webpack-plugin, webpack4内置了uglifyjs, 当mode是production的时候,会默认进行压缩。
css压缩:optimize-css-assets-webpack-plugin,同时使用预处理器cssnano
安装依赖
yarn add --dev cssnano optimize-css-assets-webpack-plugin
配置
plugins: [
new OptimizeCssAssetsWebpackPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
}),
]
Html压缩:使用强大html-webpack-plugin,我们想要生成一个html文件,就要写一个new htmlWebpackPlugin,当然写法可以优化。它最主要的作用是根据模板,编译生成一个html文件,同时把chunk指向的js/css插入到html中。这里主要是通过minify设置压缩模式
plugins: [
new htmlWebpackPlugin({
template: path.join(__dirname, "src/search.html"),
filename: 'search.html',
chunk: ['search'],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
})
]
参考来自
极客时间的webpack课程:time.geekbang.org/course/intr…