webpack 的 使用
前言
- webpack 作为前端主要的模块化打包工具,我们是必然需要去掌握,理解其用法的。接下来我们就来一起学习 webpack 吧 ☺️
创建项目 webpack-project 文件夹
- npm 或 yarn 包下载器 任选一个 我们这里就是用 yarn
- 我们在项目根目录 通过 yarn init -y 生成默认 package.json 包管理文件
yarn init -y
- 安装 webpack webpack-cli
yarn add webpack webpack-cli -D
- webpack 默认有打包入口和出口
打包入口 src/index.js
输出出口 dist/main.js
- 执行 yarn webpack 就可以生成 dist 打包目录了
webpack 或
yarn webpack
- webpack 执行命令 mode 默认为 production webpack 默认会帮你进行代码压缩
自定义配置 创建 webpack.congfig.js ( wepacke 会读取 webpack.config.js 配置 )
webpack 五个核心概念
- entry
- 指定入口文件
- output
- 输出文件,位置,文件名
- loader 翻译官
- 处理非 js 文件,webpack 自身只能打包 js 或 json
如:css,img,font,html 等一系列文件 将其打包成 js 模块
- plugins 压缩,版本
- 扩展 webpack 的功能
- mode
- 可以设置 development,production,none 这个详情见中文官网
- optimization 最佳化
- 可以设置代码切割,树摇等一些列操作, 生产模式下自动开启
entry
// entry 可以是string,array , object 类型 这里我设为了object 既可以多入口也可单入口 😝
// 入口文件路径 如果是相对路径不可以省略 ./
entry: { bundle: "./src/index.js" },
- 扩展
// String 单入口 会打包生成一个默认名 main.js 的 chunk包
entry: path.join(__dirname, "/src/index.js"),
//Array 多入口还是会打包生成一个默认名 main.js 的 chunk包 , 主要是开发环境 html中的hmr
entry:[path.join(__dirname, "/src/index.js"),path.join(__dirname, "/src/test.js")]
//Object 生成多个chunk
entry: {
index: path.join(__dirname, "/src/index.js"),
test: path.join(__dirname, "/src/test.js"),
},
// 特殊用法 就是object和array 相结合
在dll中 vue vue-router vuex 可以打包成一个chunk模块
entry:{
index:[path.join(__dirname, "/src/index.js"),path.join(__dirname, "/src/add.js")]
test: path.join(__dirname, "/src/test.js"),
}
output
//出口文件配置
output: {
//输出的路径,当前项目更路径生成dist目录
path: path.resolve(__dirname, "dist"),
//输出的文件名称 dist/js/bundle.js
filename: "js/[name].js",
// 模块资源引用路径 通常 dist 会放在服务器端 作为文件更路径 👌
publicPath: "/",
},
- 扩展
output: {
// 文件位置/文件名
filename: "js/[name].[contenthash:6].build.js",
// 所有资源的公共目录位置
path: path.join(__dirname, "dist"),
//所有资源的公共路径
publicPath: "/",
// 拆分的chunk命名规则
chunkFilename:[name]_chunk.js,
//chunk暴露的变量
library: [name],
//变量名添加到那个对象上 window commonjs global umd
libraryTarget: "umd",
},
loader
module:{
rules:[
// 添加各种静态资源模块文件
... loaders
]
}
css 文件解析加载
- css-loader 将 css 文件转成 js 模块
yarn add css-loader -D
- style-loader 将 js 模块中的 css 标识 创建 style 标签插入
yarn add style-loader -D
- 基本用法
{
// 要匹配的文件名
test: /\.css$/,
use: [
//从下往上执行
// 创建style标签会将 下面的js文件插入进去 ,放在head标签中
"style-loader",
//将css 文件变成commonJs模块加载js中 样式字符串
"css-loader",
],
},
字体,图片 文件解析加载
- file-loader 就是将文件复制到了指定目录
yarn add file-loader -D
- 基本用法
{
test: /\.(otf|eot|svg|ttf|woff|woff2)(\?\S*)?$/,
loader: "file-loader",
options: {
// 输出目录
outputPath: "fonts",
},
},
处理图片 转成 base64 减小服务器压力,增加包的体积, 一般我们处理 4k 以下的小图片 超过 4k 会类似 file-loader 一样导出文件
yarn add url-loader -D
- 基本用法
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: "url-loader",
options: {
limit: 4 * 1024,
// 图片的路径 hash8位,后缀名
name: "[name].[hash:8].[ext]",
//打包输出的地址
outputPath: "img",
//使用commonJs 解析, 新版无需添加 😬
esModule: false,
},
},
],
},
处理 html 文件 解析 html 文件中的 img src a href 等( 新版本有点兼容问题,我这用 1.3.2 版本的 😺)
yarn add html-loader@1.3.2 -D
- 基本用法
{
test: /\.(html)$/,
use: [
{
loader: "html-loader",
options: {
esModule: false,
attributes: {
list: [
{
tag: "img",
attribute: "src",
type: "src",
},
{
tag: "img",
attribute: "data-src",
type: "src",
},
{
tag: "img",
attribute: "data-srcset",
type: "srcset",
},
{
tag: "a",
attribute: "href",
type: "src",
},
],
},
},
},
],
},
es6 语法装 es6 ,兼容老版本浏览器,不能识别 es6 语法
yarn add babel-loader @babel/core @babel/preset-env -D
- 基本用法
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
- 扩展 (生产兼容)
以上只是解决了部分 兼容性问题 碰到 ie 这种狗比浏览器 有些还是有问题 如 Promise
- 暴力解决 全部 js 兼容性问题 缺点打包后的体积变大
yarn add @babel/polyfill -D
无需配置 直接 esmodule 导入即可
import "@babel/polyfill"
- 按需加载 core-js
yarn add core-js -D
- 这里我配置了一些基本浏览器的参数,兼容版本
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: [
//放在某个loader的后面
// 启动时间600ms ,通信时间也要
// 所以不是必要,别滥用
{
loader: "thread-loader",
options: {
worker: 2, //开启进程两个
},
},
{
loader: 'babel-loader',
options: {
// 开启babel 缓存
// 第二次构建后,会读取之前的缓存
cacheDirectory: true,
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: "usage",
// 指定core-js的版本
corejs: {
version: 3,
},
//指定兼容浏览器的版本
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
}
]
]
}
}
]
}
总结理解 loader 的工作原理
-
loader 就是讲匹配到的资源文件,进行一些的处理,返回 js 字符串代码,统一打包到 js 模块中
-
接下来我们来自定义一个 loader
- 我们要将一个 hello_markdown.md 文件中的内容进行解析
- 项目根目录下创建一个 markdown-loader.js 文件
- 安装一个 marked,用来解析 markdown 文件
- return 返回的必须是 js 的字符串格式
- 总结 loader 就是处理资源文件数据的一个个管道
yarn add marked -D
const marked = require("marked");
module.exports = (source) => {
let html = marked(source);
// 直接导出
// return `module.exports = ${JSON.stringify(html)} `;
// return `export default ${JSON.stringify(html)} `;
// 在通过 html-loader 处理
return html;
};
- 基本用法
{
test: /\.md$/,
use: [
// 直接导出,不需要html-loader 再次处理
"html-loader",
{
loader: "./markdown-loader",
},
],
},
plugins(插件))
plugins:[
...
]
clean-webpack-plugin 打包时自动清除上一个 dist
yarn add clean-webpack-plugin -D
- 基本用法
//用于在构建前清除dist目录中的内容
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
plugins:[
new CleanWebpackPlugin()
]
html-webpack-plugin 打包时自动帮你生成 html 模版 并引入 link css 打包后的 js
yarn add html-webpack-plugin -D
- 这里的 html-webpack-plugin 自定义变量会与 html-loader 冲突 导致 不能输出变量 大坑啊!!! 🤷♀️ 文章参考
- 好在 vue,react 这些项目中也不会去使用 ejs 语法 ,我这边就不把 html-loader 去掉了或者不用自定义变量 也没什么卵用
- 解决方法 1.去掉 html-loader 2.不用 ejs 字面量
- 基本使用
//复制 html文件 并自动注册打包后 js文件
const HtmlWebpackPlugin = require("html-webpack-plugin");
plugins:[
new HtmlWebpackPlugin({
// 自定义变量
// title:'my webpack'
// 自定模块
template: "./public/index.html",
}),
]
copy-webpack-plugin 打包复制静态资源 就是不需要经过 loader 处理的资源文件
yarn add copy-webpack-plugin -D
- 基本使用
const CopyWebpackPlugin = require("copy-webpack-plugin");
new CopyWebpackPlugin({
patterns: [
{
from: path.resolve(__dirname, "public/static"),
to: path.join(__dirname, "dist/static"),
},
],
}),
webpack.DefinePlugin 全局注入变量, 不同环境,可以设置不同的服务器地址
- 基本使用
let env = {
title:'标题'
}
const webpack = require("webpack");
new webpack.DefinePlugin({
env: JSON.stringify(env),
}),
webpackbar 打包进度条插件
yarn add webpackbar -D
- 基本使用
const WebpackBar = require("webpackbar");
// 添加 进度条
new WebpackBar(),
webpack-merge webpack 配置合并
- 基本使用
const { merge } = require("webpack-merge");
module.exports = merge(base,{
....
})
总结理解 plugins 的工作原理
-
plugins 相比于 loader 能力更强 loader 只是在加载模块时进行工作 😺
-
接下来我们来自定义一个 plugins
- webpack 在处理文件时 定义了一系列的钩子,我们可以在不同的钩子节点中去扩展我们的插件
- 我们现在根目录下定义一个 my-plugin.js 文件
// 自定义插件
module.exports = function () {
// wepack 会去执行实例化对象中的 apply 方法
this.apply = function (compiler) {
// 文件即将要输出的钩子函数
compiler.hooks.emit.tap("MyPlugin", (compilation) => {
for (const name in compilation.assets) {
if (name.endsWith(".js")) {
let content = compilation.assets[name].source();
content = content.replace(/\/\*\*+\*\//g, "");
compilation.assets[name] = {
source() {
return content;
},
size() {
return content.size;
},
};
}
}
});
};
};
基本使用
const MyPlugin = require("./myPlugins.js");
new MyPlugin(),
optimization(最佳性能优化)
- 扩展
// 代码分割
optimization: {
splitChunks: {
chunks: "all",
//---------------以下都是默认值--------------
//最小拆分大小 30kb
minSize: 30 * 1024,
//最大没有限制
maxSize: 0,
//要提取的Chunk最少一次
minChunks: 1,
// 按需加载时候最大的并行请求数
maxAsyncRequests: 5,
//一个入口最大的并行请求数
maxInitialRequests: 3,
// 文件名称分隔符号~
automaticNameDelimiter: "~",
//可以使用命名规则
name: true,
cacheGroups: {
//分割chunk租
//node_modules文件会被打包到 vendors 组中的chunk vendors.XXX.js
vendors: {
test: /[\\/]node_modules[\\/]/, //匹配规则
priority: -10, //优先级
},
default: {
minChunks: 2,
priority: -20, //优先级
reuseExistingChunk: true, //是否复用存在的chunk
},
},
},
},
这里有个小问题关于缓存的
拆分后可能,某个文件发生变化,关联文件也会变化,导致缓存失效
// 拆分的chunk命名规则
chunkFilename: "[name].[contenthash:6]_chunk.js",
// 代码分割
optimization: {
runtimeChunk: {
name: (h) => `runtime_${h.name}`,
},
},
resolve
- 基本使用 参考文章
resolve: {
//路径别名, 缺点,vscode 找文件不好找了 🤷♀️
alias: {
Utilities: path.resolve(__dirname, "src/utilities/"),
Templates: path.resolve(__dirname, "src/templates/"),
},
//忽略后缀名
extensions: [".js", ".json", ".css"],
//指定modules
modules: ["node_modules"]
},
开发环境 提高开发效率 (打包速度快,方便调试)
通过 webpack 自带的 watch 对开发文件进行监视,变动立即打包,
yarn webpack --watch
通过 vscode 插件 Live Server 开启打包文件监视刷新
- 总结这种虽然实现了文件打包,刷新 但是打包读写磁盘效率太低,配置麻烦
webpack-dev-server 开发服务器 内置热更新
HMR 热模块替换
-
优化打包速度 HMR 热模块替换 作用是一个模块发生变化时候,不会刷新浏览器,导致其他文件内容丢失
-
样式文件:可以使用 HMR 功能 自带的 style-loader 内部实现了
-
js 文件:默认不能使用 HMR 功能
html 文件:默认不能使用 HMR 功能,同时会导致问题:HTML 文件不能热更新
:修改 entry 入口,HTML 文件加入到 spa 中不同 mpa 中不同 -
在 devServer 中添加 hot:true 开启 HMR 功能
-
现在 vue,react 等脚手架为什么可以自动热更新呢?(`ヘ ´)=3
-
js 热更新是没有规律的, vue,react 文件导出都做了规定,导出函数,导出类 这样就确定了规范
// 处理js模块不能热更新
if(module.hot){
module.hot.accept('js文件',()=>{
//执行方法
})
}
// 创建静态服务器 进行webpack 命令打包到内存中
devServer: {
proxy: {
"/apis": {
target: "http://8.209.246.174:10000/",
changeOrigin: true, // 如果接口跨域,需要进行这个参数配置
//ws: true, // proxy websockets
//pathRewrite方法重写url
pathRewrite: {
"^/apis": "/apis",
},
},
},
//静态资源目录
contentBase: "./public",
//gzip 压缩
compress: true,
//端口号
port: 4000,
//热更新,不需要刷新浏览器 大大提高开发速度 hot 跟 hotOnly hotOnly 热替换失败不会自动刷新便于找到问题
hotOnly: true,
//开启
open: false,
},
- 扩展
- 由于配置了 mini-css-extract-plugin 不使用 style-loader 会导致 css 不热更新
解决方法: 开发环境用 style-loader 生产用 MiniCssExtractPlugin.loader (〃>皿<)
- devSever 详细配置
devServer: {
// 文件目录
contentBase: path.join(__dirname, "dist"),
//监视文件目录
watchContentBase: true
//监听配置
watchOptions: {
poll: true,
//忽略node_modules变动更新
ignored: /node_modules/,
},
//开启文件gzip压缩加载速度更快
compress: true,
//端口号9000
port: 9000,
//host:localhost
host: "localhost",
//开启热替换
hot: true,
//自动启动浏览器
open: true,
//取消错误日志
clientLogLevel: "none"
//除了初始启动信息之外的任何内容都不会被打印到控制台
quiet: true,
//出现错误,不要满屏提示
overlay: true
//代理
proxy: {
"/api": {
//ajax 请求服务器
target: "http://localhost:3000",
//重写
pathRewrite: {"^/api" : ""}
}
}
}
souce-map 源代码地图调试
-
souce-map:一种 提供源代码到构建后 代码映射拘束(简单的说构建后代码出错了,通过映射可以追踪源代码)
-
开启方式也十分简单
我们针对开发环境下, 速度快,查看,调试方便
devtool:'eval-source-map'
生产环境 不要暴露源代码
devtool: "nosources-source-map"
生产环境 提高运行效率 (打包速度快,性能高)
mini-css-extract-plugin 将 css 单独打包出来,较小包的体积( 文件>150kb css 文件多,内容多时使用,不然浪费一次请求时间) 一般项目都超过 150k 所以算是生产环境优化吧 😜
- 由于 css 是嵌入在 js 中的,加载 js 才会创建 style 标签插入 head 中 会出现闪屏现象
作用: 减小 build.js 体积 解决闪屏现象
yarn add mini-css-extract-plugin -D
- 基本使用
// css 分离 较小包的体积
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// loader 配置
{
// 要匹配的文件名
test: /\.css$/,
use: [
// 不需要style-loader 去生产style标签了,去你丫的 🙆♂️
{
loader: MiniCssExtractPlugin.loader,
options: {
// 可以设置 css 图片引用的值 如http请求
// publicPath: "/img/",
},
//将css 文件变成commonJs模块加载js中 样式字符串
"css-loader",
],
},
// plugins 配置
new MiniCssExtractPlugin({
filename: "css/[hash:8].[name].css",
}),
postcss-loader postcss-preset-env 解决大部分浏览器 css3 兼容性问题 如 -webkit-backface-visibility: hidden;
yarn add postcss-loader@3 postcss-preset-env -D
- 基本使用
// 因为都是处理css 文件 所以又要动css的loader了 凸(艹皿艹 )
{
// 要匹配的文件名
test: /\.css$/,
use: [
// 不需要style-loader 去生产style标签了,去你丫的 🙆♂️
{
loader: MiniCssExtractPlugin.loader,
options: {
// 可以设置 css 图片引用的值 如http请求
// publicPath: "/img/",
},
//将css 文件变成commonJs模块加载js中 样式字符串
"css-loader",
// css 兼容性处理
// 会自动读取 package.json 中的文件
// package.json 配置
// "browserslist": {
// "development": [
// "last 1 chrome version",
// "last 1 firefox version",
// "last 1 safari version"
// ],
// "production": [
// "> 0.2%",
// "not dead"
// ]
// }
{
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [
//postcss插件 帮postcss找到package.json browerslist
require("postcss-preset-env")(),
],
},
},
],
},
webpack5 以上 使用 optimize-css-assets-webpack-plugin 单独的 css 文件进行压缩处理
- 温馨提示 webpack5 以下使用 css-minimizer-webpack-plugin
yarn add optimize-css-assets-webpack-plugin -D
- 基本使用
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
// 在 plugins 添加
new OptimizeCssAssetsWebpackPlugin(),
eslint 规范代码风格 ( 个人还是喜欢 团队规范代码风格 )
yarn add eslint-loader eslint -D
- 基本使用
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
//优先执行 //babel-loader 转换后后执行的话会报错
enforce: "pre",
options: {
// 自动修复 eslint 错误
fix: true,
},
},
- 配置规范 artbnb eslint-config-airbnb-base 官网
yarn add eslint-plugin-import -D
yarn add eslint-config-airbnb-base -D
在 package.json 中配置 使用 artbnb 规范
"eslintConfig": {
"extends":"artbnb-base",
"env":{
"browser":true
}
}
压缩 html 文件
- 新版 mode 为 production 自动压缩
- 旧版 html-webpack-plugin,需如下配置
new HtmlWebpackPlugin({
// 复制模版
template: "./public/index.html",
minify:{
// 删除空格
collapseWhitespace:true,
// 去除注释
removeComments:true
}
}),
oneOf loader 只命中一次就结束,不用每个都去过一遍,提高打包构建速度
基本使用
rules:[
//每次都会执行
...loaders
{
// 命中就执行
oneOf:[
...loaders
]
}
]
缓存
babel 缓存 (开发,生产打包优化)
- 试想一下 如果我只改动了一个 js 模块,导致全部的 js 文件在重新构建打包一下,势必会导致打包速度的减慢,所以我们需要缓存,将只编译一个文件替换就行
详情见 bable loader
添加一下配置
cacheDirectory: true,
文件资源缓存 (上线优化)
-
需要去了解一下,强缓存和协商缓存的概念点击了解
-
需要用过服务端去设置
-
不管后端, 我们前端需要做的当文件发生修改时生成不同的文件就行,这样浏览器就会再次请求新的文件
-
解决 文件资源缓存
-
通过 hash 的方式,我们虽然可以获取最新的文件,但是有些 css 文件没有修改同样也进行了更新
(这种就是,变了一个文件,所以文件名都变了,相当于就没有缓存的效果了) -
通过 chunkhash 也可以生成不同的 hash 值,来更新文件,但是 如果 css 在同一个 chunk 中还是一样会被更新
(这种就是,变了一个文件,在同一个 chunk 中的文件 也会变) -
通过 contenthash 根据文件的内容来生成 hash 值
(这种就是,变了一个文件,只改该文件,以及连带文件,效果最好)
- 总结
- 前端文件增加了 hash 当文件发生变化时,再次刷新浏览器,就会获取新的资源文件
- 这里我发现 通过 url-loader 转换 base64 居然有缓存,我把它改成 hash,就好了,奇怪了 凸(艹皿艹 ) 🤷♀️
tree shaking(树摇) 删除我们无用的代码 必须 es6Module(减小包的体积)
optimization: {
// 树摇功能,标记 commonJs打包不导入的文件
usedExports: true,
// 摇下来 哪些不导出的代码
minimize: true,
// 合并函数,尽可能将模块合并到同一个执行函数中,又提高运行效率
concatenateModules:true
},
1.这里要解析一下什么是文件的副副作用
打个比方
import '../index.css'
import 'xxx.js'
以上直接通过 import ‘…/xx’ 进来都会被摇调
在 package.json 文件中
'sideEffects':['xxx.js',"*css"] // fasle 全部文件无副作用 一般不可能 ,这里我直接设置true 😺
code split 代码分割 按需加载 (资源太大也不行,加载慢, 太小,http 并发请求太多。浪费带宽)
多页面打包 抽取公共部分
- webpack 可以多页面打包
entry: {
page1: "./src/page1.js"
page2: "./src/page2.js"
},
output:{
filename:[name].[contenthash:8].bundle.js
}
new HtmlWebpackPlugin({
title: "page1",
filename: "page1.html",
template: "./public/index.html",
}),
new HtmlWebpackPlugin({
title: "page2",
filename: "page2.html",
template: "./public/index.html",
}),
设想一下 如果 page1.js,page12.js 都引入了 jquery ,那两个包的体积都包含了 jquery
我们是否可以将 jquery 提取出来 成为一个公共的模块,在分别引入这两个 html 中? 👌
optimization: {
splitChunks: {
chunks: "all",
},
}
动态加载 import(‘xxxx’)
这个是老朋友了 vue 中的路由懒加载不就是这个嘛
// 5s 后请求加载该资源文件
setTimeout(() => {
import(/* webpackChunkName:"module" */"./module.js"
}, 5000);
魔法注释 分包名称
/* webpackChunkName:"module" */
- 打包编译之后 5s 后 通过 script 标签去请求该 js 文件
懒加载和预加载
懒加载作用顾名思义 就是我要用是加载
需要结合上面的代码分割技术
btn.onclick = () => {
import(/* webpackChunkName: 'hmr'*/ "./hmr.js").then(
(res) => {
console.log(res.default);
}
);
};
预加载 移动端兼容性较差 过几年应该可以使用 (项目中有一个比较大的模块,我们可以进行预加载)
webpackPrefetch: true 预加载移动端兼容性较差
btn.onclick = () => {
import(/* webpackChunkName: 'hmr', webpackPrefetch: true*/ "./hmr.js").then(
(res) => {
console.log(res.default);
}
);
};
PWA 渐进式网络开发应用程序 (离线缓存技术)
在 webpack 中要想使用该技术要用到一个插件 运行条件:必须在服务器上
yarn add workbox-webpack-plugin -D
- 基本使用
const WorkboxWebpackPlugin = require("workbox-webpack-plugin");
//在 plugins添加 会自动帮你 生成 service-worker.js 文件
new WorkboxWebpackPlugin.GenerateSW({
/*
* 1.帮助serviceworker 快速启动
* 2.输出旧的serviceworker
* 生成serviceworker.js 文件
*/
clientsClaim: true,
skipWaiting: true,
}),
在 index.js 文件中注册 service-worker.js
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/service-worker.js")
.then(() => {
console.log("注册成功");
})
.catch((err) => {
console.log("注册失败");
});
});
}
多进程打包 适用项目体积大的时候使用,加快打包速度
js 运行时单线程的
需要下载一个 loader thread-loader
yarn add thread-loader -D
- 基本使用
详情见 bable loader
添加一下配置
//放在某个loader的后面
// 启动时间600ms ,通信时间也要
// 所以不是必要,别滥用
{
loader: "thread-loader",
options: {
worker: 2, //开启进程两个
},
},
忽略要打包的 node_module 中的库 减小打包体积 多数采用 cdn 加速引入
在 webpack.config.js 中添加 externals
//去除打包node_module中库
externals: {
// 忽略库名 npm包名
jquery: "jQuery",
},
dll 忽略要打包的 node_module 中的库 将 node_module 中的库文件单独打包出来,不用 cdn 引入 不建议这样使用 还是 cdn 引入好
- 项目根目录创建 webpack.dll.js 这里我们就单独打包出来了 jquery.js,jquery.json, bootstrap.js ,bootstrap.json
const path = require("path");
const webpack = require("webpack");
module.exports = {
// 单入口
entry: {
// 要打包的库是jquery
jquery: ["jquery"],
bootstrap: ["bootstrap"],
},
//出口
output: {
// 位置
path: path.resolve(__dirname, "dll"),
// 文件名
filename: "[name].js",
library: "[name]_[hash:10]", //打包的库里面向外暴露出去的名字是什么
},
//插件
plugins: [
new webpack.DllPlugin({
name: "[name]_[hash:10]",
path: path.resolve(__dirname, "dll/[name].json"),
}),
],
mode: "production", // development || production 可以在--mode= 层级更高指定
};
- 接着在 webpack.config.js plugins 添加 告诉 webpack 哪些库不用打包 同时名字也要变
const webpack = require("webpack");
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll/jquery.json"),
}),
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "dll/bootstrap.json"),
}),
由于忽略了 jquery bootstrap 需要引入 dll 文件夹中的两个文件
- 这里我们需要一个插件 add-asset-html-webpack-plugin
将打包出去的文件引进来,在 html 中引入
yarn add add-asset-html-webpack-plugin -D
- 接着在 webpack.config.js plugins 添加
// 将打包出去的文件引进来,
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll/jquery.js"),
}),
// 将打包出去的文件引进来,在html中引入
new AddAssetHtmlWebpackPlugin({
filepath: path.resolve(__dirname, "dll/bootstrap.js"),
}),
- 这样第一次打包会将 dll 文件夹中 jquery,bootstrap 打包到 dist 文件夹中
并且生成了 script 标签自动引入,打包第二次不会加载