文章目录
前言
webpack是一套基于NodeJS的"模块打包工具"。
webpack能够打包JS模块, 还可以打包CSS/LESS/SCSS/图片等其它文件。
为了方便代码的维护和复用,我们将不同的功能写入不同的模块。
结果导致:
- 导入资源变多了, 请求次数变多了, 网页性能也就差了
- 不同功能都放到了不同模块中了, 那么如何维护模块之间的关系也变成一个难题了
- 等等…
所以利用webpack在项目上线时将用到的所有模块都合并到一个文件中。
在index.html中只导入主文件, 再主文件中再导入依赖模块。
如果想要直接使用webpack请直接去 6 总结部分~ |
1 如何通过webpack来打包JS模块
测试版本:
node:v14.16.1
npm:6.14.12
webpack:4.41.6
webpack-cli:3.3.9
1.1 通过命令行的方式打包文件
- 安装webpack
npm init -y
npm install --save-dev webpack@4.41.6
(简写:npm i webpack@4.41.6 -D
)
npm install --save-dev webpack-cli@3.3.9
- 在终端中输入打包的指令(含义:利用webpack将index.js和它依赖的模块打包到一个文件中)
npx webpack index.js
npx webpack index.js --mode development
打包的模式是 以 开发的 模式打包 - 注意点:
index.js就是需要打包的文件
打包之后的文件会放到dist目录中, 名称叫做main.js
1.2 通过配置文件的方式打包文件
webpack常见配置
1.entry: 需要打包的文件
2.output: 打包之后输出路径和文件名称
3.mode: 打包模式 development/production
development: 不会压缩打包后的JS代码 开发模式
production: 会自动压缩打包后的JS代码 项目模式
注意点:
- 配置文件的名称必须叫做: webpack.config.js, 然后写入以下内容,否则直接输入
npx webpack
打包会出错。
webpack.config.js内容:
const path = require('path');
module.exports = {
mode:"development", // "development" 开发模式 | "production" 项目模式
entry: './src/index.js', // 指定要打包的入口
output: { // 配置打包后输入的路径和打包的文件名
filename: 'bundle.js',
path: path.resolve(__dirname, 'bundle'), // 配置打包后输入路径
},
};
- 如果要使用其它名称, 那么在输入打包命令时候必须通过
--config
指定配置文件名称
npx webpack --config xxx
但这样仍然复杂,可以通过npm script来简化这个操作。
在scripts脚本这里加上:"dev":"npx webpack --config webpack.config.js"
即可。
运行指令则成了:npm run dev
1.3 webpack-sourcemap
为了便于调试和存储打包后代码和打包之前代码的映射关系
的文件我们就称之为sourcemap。
webpack官方传送门:webpack-sourcemap
- 在webpack.config.js中添加
devtool: “xxx”, - 各配置项说明:
1)eval:
不会单独生成sourcemap文件, 会将映射关系存储到打包的文件中, 并且通过eval存储
优势: 性能最好
缺点: 业务逻辑比较复杂时候提示信息可能不全面不正确
2)source-map:
会单独生成sourcemap文件, 通过单独文件来存储映射关系
优势: 提示信息全面,可以直接定位到错误代码的行和列
缺点: 打包速度慢
3)inline:
不会单独生成sourcemap文件, 会将映射关系存储到打包的文件中, 并且通过base64字符串形式存储
4)cheap:
生成的映射信息只能定位到错误行不能定位到错误列
5)module:
不仅希望存储我们代码的映射关系, 还希望存储第三方模块映射关系, 以便于第三方模块出错时也能更好的排错
const path = require('path');
module.exports = {
devtool:"cheap-module-source-map",//==================================
mode:"development", // "development" 开发模式 | "production" 项目模式
entry: './src/index.js', // 指定要打包的入口
output: { // 配置打包后输入的路径和打包的文件名
filename: 'bundle.js',
path: path.resolve(__dirname, 'bundle'), // 配置打包后输入路径
},
};
development: cheap-module-eval-source-map
只需要行错误信息, 并且包含第三方模块错误信息, 并且不会生成单独sourcemap文件
production: cheap-module-source-map
只需要行错误信息, 并且包含第三方模块错误信息, 并且会生成单独sourcemap文件
2 loader(装载机)
webapck的本质是一个模块打包工具,所以webpack默认只能处理JS文件,不能处理其他文件,为了能够让webpack能够对其它的文件类型进行打包,在打包之前就必须将其它类型文件转换为webpack能够识别处理的模块。
用于将其它类型文件转换为webpack能够识别处理模块的工具我们就称之为loader。
loader特点
- 单一原则, 一个loader只做一件事情
- 多个loader会按照从右至左,从下至上的顺序执行
1)例如: 从右至左
[ 'style-loader', 'css-loader' ]
先执行css-loader解析css文件关系拿到所有内容,
再执行style-loader将内容插入到HTML的HEAD代码中
2)例如: 从下至上
[{
loader: "style-loader"
},{
loader: "css-loader"
}]
先执行css-loader解析css文件关系拿到所有内容,
再执行style-loader将内容插入到HTML的HEAD代码中
2.1 file-loader
webpack官方传送门:file-loader
file-loader可以根据正则表达式内容打包不同格式的文件,包括图片、字体等。
1)安装file-loader:
npm install --save-dev file-loader
2)在webpack.config.js中配置file-loader
// 配置各种loader
// { test: /\.(png|jpg|gif)$/, use: 'file-loader' }
module: {
rules: [
{
test: /\.(png|jpg|gif)$/, use: [//打包图片
{
loader: "file-loader",
options:{
// 指定打包后的文件名
//这里表示和之前的文件名文件后缀名一致
name:'[name].[ext]',// 指定打包后的文件名
outputPath:"images/",// 指定打包后的文件存放的目录
publicPath:'./dist/images',//指定引用的文件的路径 这里我是用外部html引用dist目录下文件
}
}
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/, use:[//打包字体
{
loader: "file-loader",
options:{
name: "[name].[ext]",
outputPath: "font/",
}
}
]
},
]
}
可能是由于版本问题:
事实证明,是没有打包html文件,所以产生了路径问题…
2.2 url-loader
webpack官方传送门:url-loader
url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。相当于其加强版。
转化的 DataURL地址经测试使用没有bug。但使用正常地址也需要如上个file-loader加上publicPath。
1)安装urlloader
npm install --save-dev url-loader
2)配置urlloader
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: "[name].[ext]",//这里表示和之前的文件名文件后缀名一致
outputPath: "/images",// 指定打包后的文件存放的目录
limit: 1024*10// 如果你的图片小于5KB,就会把你的图片,转成base64,放到main.js
esModule: false, // 该项默认为true,改为false即可 解决html-withimg-loader路径出现default问题
}
}
]
}
limit: 1024*10
// 如果你的图片小于5KB,就会把你的图片,转成base64,放到main.js。
优势:
图片比较小的时候直接转换成base64字符串图片, 减少请求次数。
图片比较大的时候由于生成的base64字符串图片也比较大, 就保持原有的图片。
2.3 css-loader和less-loader和sass-loader
用于将CSS文件转换为webpack能够处理的类型。
1)安装css-loader
npm install --save-dev css-loader
2)安装style-loader
npm install style-loader@1.0.0 --save-dev
3)安装less
npm install --save-dev less@3.10.3
4)安装less-loader(less-loader依赖less模块,需要安装less)
npm install --save-dev less-loader@5.0.0
5)安装scss
npm install --save-dev node-sass
6)安装sass-loader
npm install --save-dev sass-loader
css-loader:把css文件翻译成JS模块 webpack就可以打包
style-loader:将webpack处理之后的css,插入到head标签中,作为内部样式
less-loader:自动将less转换为CSS
sass-loader:自动将scss转换为CSS
{
// test: /\.css$/, use:["style-loader","css-loader"]
test:/\.css$/,use:[{
loader:"style-loader"
},{
loader:"css-loader"
}]
},
{
test:/\.less$/,use:[{
loader:"style-loader"
},{
loader:"css-loader"
},{
loader:"less-loader"
},
{
test: /\.scss$/,use: [{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Sass 编译成 CSS
}
]
}]
}
注意点:
因为loader是从右至左``从下至上
,所以必须先由less-loader处理往后才能交给其他loader处理。
2.4 html-withimg-loader
- 我们通过file-loader或者url-loader已经可以将JS或者CSS中用到的图片打包到指定目录中了
- 但是file-loader或者url-loader并不能将HTML中用到的图片打包到指定目录中
- 所以此时我们就需要再借助一个名称叫做"html-withimg-loader"的加载器来实现HTML中图片的打包
使用:介绍
- 安装html-withimg-loader
npm install html-withimg-loader --save
- 配置html-withimg-loader
test: /\.(htm|html)$/i, use:["html-withimg-loader"]
如果最终路径出现default:修改url-loader中esModule: false, // 该项默认为true,改为false即可
2.5 image-webpack-loader/img-loader压缩图片
压缩可以减少网页体积, 合并可以减少请求次数。
使用方法传送门:
img-loader
image-webpack-loader
3 plugin(插件)
- plugin 用于扩展webpack的功能
- 当然loader也是变相的扩展了webpack ,但是它只专注于转化文件这一个领域。
- 而plugin的功能更加的丰富,而不仅局限于资源的加载。
1)html-webpack-plugin
2)clean-webpack-plugin
3)copy-webpack-plugin
-
HtmlWebpackPlugin会在打包结束之后自动创建一个index.html, 并将打包好的JS自动引入到这个文件中。
-
webpack-clean-plugin会在打包之前将我们指定的文件夹清空
应用场景每次打包前将dist目录清空, 然后再存放新打包的内容, 避免新老混淆问题。 -
当文档内容是固定不变的, 我们使用copy-webpack-plugin将对应的文件拷贝到打包目录中
webpack官方传送门:html-webpack-plugin
1)安装HtmlWebpackPlugin
npm install --save-dev html-webpack-plugin@4.0.0
2)安装clean-webpack-plugin
npm install --save-dev clean-webpack-plugin@3.0.0
3)安装copy-webpack-plugin
npm install --save-dev copy-webpack-plugin@5.0.5
2)配置HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [new HtmlWebpackPlugin()]
///
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [new CleanWebpackPlugin()]
///
const CopyPlugin = require("copy-webpack-plugin");
plugins: [new CopyWebpackPlugin([
{from:"doc", to:"./doc"}
])];
例:
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",//指定生成路径和文件名
minify: {
// 表示打包好后html文件需要压缩
collapseWhitespace: true
// ...
}
}),
new CleanWebpackPlugin(),
new CopyPlugin([
{
from:"./src/doc",
to:"doc"
}
]),
]
mini-css-extract-plugin
mini-css-extract-plugin是一个专门用于将打包的CSS内容提取到单独文件的插件
前面我们通过style-loader打包的CSS都是直接插入到head中的
1)mini-css-extract-plugin安装
npm install --save-dev mini-css-extract-plugin@1.1.0
2)配置mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{
test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"]
},
]},
plugins: [
new MiniCssExtractPlugin({
filename: './css/[name].css',
})
]
- 替换style-loader
loader: MiniCssExtractPlugin.loader, - 注意点: 如果相关文件资源无法显示, 需要根据打包后的结构手动设置公开路径
options: {
publicPath: “xxx”
}
mini-css-extract-plugin压缩css
webpack官方传送门
1)安装CSS代码压缩插件
npm install --save-dev optimize-css-assets-webpack-plugin@5.0.3
2)导入插件
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
3)配置
new OptimizeCssAssetsPlugin({})
4 webpack-watch
webpack-watch 可以监听打包文件变化,当它们修改后会重新编译打包
4.1 watch相关配置watchOptions
1.poll: 1000 // 每隔多少时间检查一次变动
2.aggregateTimeout: // 防抖, 和函数防抖一样, 改变过程中不重新打包, 只有改变完成指定时间后才打包
3.ignored: 排除一些巨大的文件夹, 不需要监控的文件夹, 例如 node_modules
watch:true,
watchOptions:{
poll: 1000, // 每隔多少时间检查一次变动
aggregateTimeout:300, // 防抖, 和函数防抖一样, 改变过程中不重新打包, 只有改变完成指定时间后才打包
ignored:/node_modules/
},
5 webpack-dev-server(重点)
1.webpack-dev-server和watch一样可以监听文件变化
2.webpack-dev-server可以将我们打包好的程序运行在一个服务器环境下
3.webpack-dev-server可以解决企业开发中"开发阶段"的跨域问题
webpack官方传送门:webpack-dev-server
使用:
1)安装webpack-dev-server
npm install webpack-dev-server@3.8.1 --save-dev
不需要在配置文件中引入,之前你打包是靠webpack命令,现在打包就不再靠webpack,靠webpack-dev-server
使用webpackr打包:它是打包打到硬盘上了。
webpack-dev-server也可以打包,它是把包打包到内存了,速度快。(放到一个8080端口的服务器上了)
2)配置webpack-dev-server
devServer: {
contentBase: "./bundle",//告诉服务器内容的来源 当使用了html-webpack-plugin时,contentBase无效
open: true, // 打好包后,自动打开浏览器
port: 9090, // 端口
}
"start": "npx webpack-dev-server --config webpack.config.js"
命令换为这个:使用webpack-dev-server而不是原来的webpack。
配置完毕的访问主页面地址:localhost:9090
6 HMR-热更新
6.1 什么是HMR?
1.通过webpack-dev-server自动打包并没有真正的放到指定的目录中
因为读写磁盘是非常耗时和消耗性能的,
所以为了提升性能webpack-dev-server将转换好的内容直接放到了内存中
1)通过webpack-dev-server可以实现实时监听打包内容的变化,
每次打包之后都会自动刷新网页, 但是正是因为每当内容被修改时都会自动刷新网页
所以给我们带来了很多不便, 这时就需要通过HMR插件来优化调试开发
2)HMR(HotModuleReplacementPlugin)热更新插件,
会在内容发生改变的时候时时的更新修改的内容但是不会重新刷新网站
6.2 HMR使用
HotModuleReplacementPlugin是一个内置插件, 所以不需要任何安装直接引入webpack模块即可使用
1.在devServer中开启热更新
devServer: {
open: true, // 打好包后,自动打开浏览器
port: 9090,
hot: true, // 开启热更新,只要开启了热更新就不会自动刷新网页了
hotOnly: true, // 哪怕不支持热更新,也不也去刷新网页
}
2.在webpack.config.js中创建热更新插件
// 热更新插件
new Webpack.HotModuleReplacementPlugin()
6.3 使用注意:
- 如果是通过style-loader来处理CSS, 那么经过前面两步就已经实现了热更新
- 如果是通过MiniCssExtractPlugin.loader来处理CSS, 那么还需要额外配置
- JS模块,系统默认不实现热更新。
CSS实现热更新
// test: /\.css$/, use: ["style-loader", "css-loader"]//通过style-loader来处理CSS
test: /\.css$/, use: [{
// MiniCssExtractPlugin.loader, 把css抽离出去
loader: MiniCssExtractPlugin.loader,
options: {
hmr: true // 之前使用MiniCssExtractPlugin.loader,要实现热更新,还需要配置如下代码
}
}, {
loader: "css-loader"
}]
此时css已经实现了热更新,js还没有。
JS模块实现热更新
手动监听模块变化,手动编写模块变化后的业务逻辑。
import addSpan from "./test"
// 调用
addSpan();
// JS模块的热更新,需要我们写代码来实现
if(module.hot){ // 判断当前有没有开启热更新
// module.hot.accept("./test.js" 告诉热更新需要监听哪一个JS模块变化了
module.hot.accept("./test.js", function () {
let oSpan = document.querySelector("span");
document.body.removeChild(oSpan);
addSpan();;
});
}
7 babel-转换ES678语法
7.1 webpack-ES6语法处理
-
在企业开发中为了兼容一些低级版本的浏览器, 我们需要将ES678高级语法转换为ES5低级语法。
-
否则在低级版本浏览器中我们的程序无法正确执行。
-
默认情况下webpack是不会将我们的代码转换成ES5低级语法的, 如果需要转换我们需要使用babel来转换。
7.2 如何使用
- 安装转换到ES5的相关包
babel-loader
: 把高级语法转化成低级语法 它和@babel/core
配合
@babel/preset-env
:包含了很多的转化规则
npm install --save-dev babel-loader @babel/core @babel/preset-env
- 配置babel
test: /\.js$/,
exclude: /node_modules/, // 不做处理的目录
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
},
装不存在代码的实现包:npm install --save @babel/polyfill
导入了polyfill,那么无论我们有没有用到不存在的语法都会打包到文件中。
这个时候如果使用的浏览器已经实现了更高版本的代码,就不需要转换,否则会增加代码体积,影响网页的性能,所以我们通过配置presets的方式来告诉webpack我们需要兼容哪些浏览器,然后babel就会根据我们的配置自动调整转换方案, 如果需要兼容的浏览器已经实现了, 就不转换了。
import "@babel/polyfill" // 直接引入的话,它会去模拟出所有的es中的高级语法
...
test: /\.js$/,
exclude: /node_modules/, // 不做处理的目录
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {
targets: {
"chrome": "58",
"ie":"10"//ie 10以下都要去转化
},
useBuiltIns: "usage" // 代码中使用到的什么新语法,不能进行转化,就进行模拟新语法
}]],
}
6 总结
一套完整的项目打包需要的配置。
需要下载:
npm init -y
然后下载:
拥有功能:监听文件变化并更新打包、打包JS文件、打包字体、打包图片(小于5KB)、打包css压缩文件…
根据上面配置的webpack.config.dev.js
文件内容如下:
const path = require('path'); // 导入path 系统模块 内置模块 处理路径
const HtmlWebpackPlugin = require('html-webpack-plugin') // 创建index.html,自动导入打包好的js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');// 在打包之前将我们指定的文件夹清空
const CopyPlugin = require("copy-webpack-plugin");// 将文档内容是固定不变的文件拷贝到打包目录中
const MiniCssExtractPlugin = require("mini-css-extract-plugin");// 打包css文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 打包css压缩文件
const Webpack = require("webpack")
module.exports = {
mode: "production",// "development" 开发模式 | "production" 项目模式
entry: './src/js/index.js', // 指定要打包的入口
output: { // 配置打包后输入的路径和打包的文件名
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),// 配置打包后输入路径
},
// 配置开发服务器 1)代理
devServer: {
open: true, // 打好包后,自动打开浏览器
port: 9090,
hot: true, // 开启热更新,只要开启了热更新就不会自动刷新网页了
hotOnly: true, // 哪怕不支持热更新,也不也去刷新网页
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 不做处理的目录
loader: "babel-loader",
options: {
presets: [["@babel/preset-env", {//转换低版本语法 兼容浏览器
targets: {
"chrome": "58",
"ie": "10"
},
useBuiltIns: "usage" // 代码中使用到的什么新语法,不能进行转化,就进行模拟新语法
}]],
}
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/, use: [//打包字体
{
loader: "file-loader",//指定使用的loader
options: {
name: "[name].[ext]",// 指定打包后的文件名
outputPath: "font/",// 指定打包后的文件存放的目录
}
}
]
},
{
test: /\.(png|jpg|gif)$/, use: [//打包图片
{
loader: "url-loader",
options: {
limit: 1024 * 5,// 如果你的图片小于5KB,就会把你的图片,转成base64,放到main.js
name: '[name].[ext]',
outputPath: "img/"
esModule: false, // 该项默认为true,改为false即可 解决最终路径出现default
}
}
]
},
{
test: /\.css$/, use: [MiniCssExtractPlugin.loader, "css-loader"]//配合下面打包css压缩文件
},
{
test: /\.less$/, use: [{//打包less文件到js包中
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
}
]
},
plugins: [
new HtmlWebpackPlugin({ //打包结束之后自动创建一个index.html, 并将打包好的JS自动引入到这个文件中。
template: "./src/index.html",
minify: {
// 表示打包好后html文件需要压缩
collapseWhitespace: true
// ...
}
}),
new CleanWebpackPlugin(),//在打包之前将我们指定的文件夹清空
new CopyPlugin([ //将对应的文件拷贝到打包目录中
{
from: "./src/doc",
to: "doc"
}
]),
new MiniCssExtractPlugin({ //配合上面打包css文件到js包中
filename: 'css/[name].css'
}),
new OptimizeCssAssetsPlugin({})//打包css压缩文件
// 热更新插件
new Webpack.HotModuleReplacementPlugin()
]
};
打包命令:npm run dev
结束…