webpack4学习笔记二:webpack入门
1、资源解析
1.1 解析ES6
解析需要使用babel-loader
安装:
npm install babel-loader -D
npm install @babel/core -D
npm install @babel/preset-env -D
设置babel对ES6的转换
新建一个文件,根目录下.babelrc
里面输入:
{
"presets": [
"@babel/preset-env"
]
}
然后设置webpack,在webpack.config.js
里面
module.exports = {
module:{
rules: [
{
test: /.js$/,
use: 'babel-loader'
}
]
}
}
1.2 解析CSS、less、sass
解析less、sass需要使用到css-loader,style-loader。
安装
npm install css-loader style-loader --dev
配置webpack
module:{
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
},
需要注意的是,use的解析是从右到左解析的,所以我们需要先设置style-loader
,后设置css-loader
,因为我们需要先使用css-loader解析然后传给style-loader。
解析less,less和sass差不多,这里写less
安装:npm install less less-loader --dev
配置:
module:{
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
},
1.3 解析图片or文件
解析图片需要用到一个file-loader
,这个loader就是用于处理文件的。
安装:npm install file-loader --dev
使用:
module:{
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test: /.(png|jpg|gif)$/,
use: 'file-loader'
}
]
},
字体文件和图片差不多。
module:{
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
test:/.(png|jpg|gif)$/,
use: 'file-loader'
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: 'file-loader'
}
]
},
1.4 url-loader
url-loader也可以处理图片和字体,可以设置较小资源自动base64. url-loader内部也有使用file-loader
module:{
rules: [
{
test:/.(png|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 10240
}
}
}
]
},
2、文件监听
文件监听是在发现源码发生变化时,自动重新构建出新的输出文件。
webpack开启监听有两种方式。
- 启动webpack命令时,带上
--watch
参数。 - 在配置
webpack.config.js
中设置watch:true
。
可以在package.json
设置watch
参数到scripts
里面,方便快捷。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"b": "webpack",
"watch": "webpack --watch"
},
缺点:每次需要手动刷新浏览器。(可以使用live server
)
设置watch:true
module.exports = {
// 默认false,不开启
watch: true,
// 开启watch才起作用
watchOptions: {
// 默认为空,不监听的文件或者文件夹,支持正则匹配
ignored: /node_modules/,
// 监听到变化后等待300ms再执行,默认300ms
aggregateTimeout: 300,
// 判断文件是否发送变化是通过不停轮询系统指定文件有没有变化实现的,默认每秒1000次
poll: 1000
}
}
2.1 文件监听的原理
轮询判断文件的最后编辑时间是否变化,某个文件发生了变化,并不会立刻告诉监听者,而是先缓存起来,等aggregateTimeout(缓存等待时间)
3、热更新
模块热更新(热替换),其目的是为了加快用户的开发速度,提高编程体验。它并不适用于生产环境,这意味着它应当只在开发环境使用。
模块热替换(HMR - Hot Module Replacement)是 webpack 提供的最有用的功能之一。它允许在运行时替换,添加,删除各种模块,而无需进行完全刷新重新加载整个页面,其思路主要有以下几个方面。
- 保留在完全重新加载页面时丢失的应用程序的状态
- 只更新改变的内容,以节省开发时间
- 调整样式更加快速,几乎等同于就在浏览器调试器中更改样式
3.1 WDS热更新
WDS:webpack-dev-server
;不刷新浏览器,不输出文件,而是放在内存中,配合使用HotModuleReplacementPlugin
插件
安装:npm install webpack-dev-server -D
配置:在package.json
里面; --open
就是打开浏览器。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"b": "webpack",
"watch": "webpack --watch",
"dev": "webpack-dev-server --open"
},
在webpack.config.js
里面
'use strict'
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "development", // 开发
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html'
}),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
// 服务的文件目录
contentBase: '/.dist',
// 开启
hot: true
},
}
3.2 WDM热更新
WDM:webpack-dev-middleware
; WDM将webpack输出的文件传输给服务器,适用于灵活的定制场景。需要一个node服务器,通常使用express
。
安装还是没什么安什么。 配置:
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('listening on port 3000');
})
3.3 热更新原理
原理:
- webpack compile(编译器):将js源代码编译成Bundle(输出的文件)
- HMR server: 将热更新的文件输出给HMR runtime
- bundle server:提供文件在浏览器的访问,本地跑一个服务来访问
- HMR runtime:运行时会被注入到浏览器的bundle.js里面,通过bandle server和服务器建立连接,更新文件的变化
- bundle.js:构建输出的文件
具体过程:
启动阶段:文件系统编译,通过webpack compile进行打包,打包好了之后把文件传输给bundle server,bundle server以开启本地服务器的方式让浏览器访问的到,然后就启动了。 文件更新:文件变化完成之后,首先经过webpack compile进行编译,编译好了之后发送给HMR server,HMR server知道哪些资源模块发生改变,发生改变之后HMR server(服务端)通知HMR runtime(客户端),通常是以json的形式传输,HMR runtime收到通知之后就会更新代码,最终代码改变并且不刷新浏览器。
4、文件指纹
文件指纹就是打包后输出的文件名的后缀。通常用来做版本管理,文件指纹和热更新无法同时使用。
4.1 文件指纹生成
- Hash:和整个项目的构建相关,只要项目文件有修改,整个项目构建的hash值就会更改。
- Chunkhash: 和webpack打包的chunk有关,不同的entry会生成不同的chunkhash值。
- Contenthash:根据文件内容来定义hash,文件内容不变,则contenthash不变。
4.2 文件指纹设置
js文件指纹设置:设置output的filename,使用[chunkhash]
output:{
filename: '[name]_[chunkhash:8].js',
path: __dirname + '/dist'
}
css文件指纹设置:由于style-loader
直接插入到页面中,并没有打包,我们需要使用插件mini-css-extract-plugin
,设置它的filename,使用contenthash, 当然插件需要安装,安装就不写了。然后style-loader
和插件的功能互斥,所以只能用一个。
module:{
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
]
},
plugins:[
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
图片的文件指纹设置:设置file-loader
的name,使用hash。
module:{
rules: [
{
test:/.(png|jpg|gif)$/,
use: {
loader: 'file-loader',
options: {
name: "[name]_[hash:8].[ext]",
}
}
}
]
},
占位符简介:
[ext]
: 资源后缀名
[name]
: 文件名称
[path]
: 文件的相对路径
[folder]
: 文件所在的文件夹
[contenthash]]
: 文件的内容hash,默认是md5生成
[hash]
: 文件内容的hash,默认是md5生成
[emoji]
: 一个随机的指代文件内容的emoji
5、代码压缩
5.1 js压缩
webpack4内置了uglifyjs-webpack-plugin
插件,运行代码就自动压缩。
5.2 css压缩
使用optimize-css-assets-webpack-plugin
、cssnano
两个插件。
安装: npm install optimize-css-assets-webpack-plugin -D
, npm install cssnano -D
使用:
const OutimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html'),
filename: 'index.html'
}),
new OutimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
],
5.3 html压缩
使用了html-webpack-plugin
,一个页面对应一个HtmlWebpackPlugin,多个页面需要创建多个。
const HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({
// 模板
template: path.join(__dirname, 'src/index.html'),
// 指定打包的文件名字
filename: 'index.html',
chunks: ['index'],
inject: true,
minify:{
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}),