webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容。
1.入门
npm i webpack
npm i webpack-cli
npx webpack “./src/main.js” –mode development
基本的webpack.config.js文件
const path = require('path');
module.exports = {
//入口
entry: "./src/index.js",
//打包的输出
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
//插件
plugins:[
],
//开发模式 和 生产模式
mode: "development",
//模块
module: {
rules: [
]
},
};
{
"name": "shopping",
"version": "1.0.0",
"description": "shopping",
"main": "./src/index.js",
"scripts": {
"package": "webpack",
"dev": "webpack server",
"built": "webpack"
},
"author": "richu",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.26.0",
"@babel/preset-env": "^7.26.0",
"babel-loader": "^9.2.1",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.6.3",
"style-loader": "^4.0.0",
"url-loader": "^4.1.1",
"webpack": "^5.96.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.1.0"
}
}
2.资源的处理
1.处理css资源
npm i css-loader style-loader -D
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
plugins:[
{
test: /\.css$/, //处理css资源
use: [
'style-loader', //将js中css通过创建style标签添加html文件中生效
'css-loader' //将css资源编译成commonJS的模块到JS中
],
},
],
mode: "development",
module: {
rules: [
]
},
};
2.处理less资源
npm i less less-loader –save-dev
module: {
rules: [
{
{
test: /\.less$/,
use: ['style-loader', 'css-loader','less-loader'],
}
]
},
3.处理sass资源
npm i sass sass-loader -D
{
test: /\.s[ac]ss$/,
use: ['style-loader', 'css-loader','sass-loader'],
}
4.处理图片资源
将图片资源转为base64
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type:"asset",
parser:{
dataUrlCondition:{
maxSize:10*1024
}
}
}
5.修改打包输出的文件目录
1.修改js的输出目录
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/bundle.js",
},
2.修改图片的输出目录
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type:"asset",
parser:{
dataUrlCondition:{
maxSize:10*1024
}
},
generator:{
//输出图片名字
filename:"images/[hash][ext]"
}
}
6.自动清空上次打包的内容
output: {
path: path.resolve(__dirname, "dist"),
filename: "js/bundle.js",
//将path对应的目录整个清空
clean:true
},
7.处理Html资源
npm i –save-dev html-webpack-plugin
new HtmlWebpackPlugin({
filename:'index.html',
template:'./src/index.html'
}),
8.搭建开发服务器
npm i webpack-dev-server -D
devServer: {
static: {
directory: path.join(__dirname, 'src'), //静态文件目录
},
compress: true, //压缩
port: 9000, //端口
},
3.eslint
1.基本配置
1.parserOptions 解析选项
2.rules 具体规则
- off 或0 关闭规则
- warn 或 1 使用警告级别的错误
- error 或 2 使用错误级别的错误
3.extends继承
2.入门
npm i eslint-webpack-plugin –save-dev
npm i eslint –save-dev
- 创建
.eslintrc.js
文件
module.exports = {
extends: [
"eslint:recommended", //继承eslint
],
env:{
node:true, //启用全局node
browser:true, //启用浏览器全局变量
},
parserOptions: {
ecmaVersion:6, //es6
sourceType:"module", //es module
},
plugins: [
],
rules: {
"no-var":2, //使用var的错误级别为2
},
}
- 创建
.eslintignore
文件
dist //忽略dist文件夹
4.babel
将es6转为向后兼容的js代码
npm i -D babel-loader @babel/core @babel/preset-env
{
test: /\.js$/,
exclude: /node_modules/, //不需要加载node_modules文件内的文件
use: [{
loader: 'babel-loader',
options:{
presets:["@babel/preset-env"]
}
}],
},
或者将OPtions写到babel.config.js
- 创建
babel.config.js
文件
module.exports = () => ({
presets: [require("@babel/preset-env")], //只能预设
});
生产模式的配置
优化代码的性能
优化代码的打包速度
mode: “production”,
5.优化
1.将css打包成单独文件
npm i –save-dev mini-css-extract-plugin
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader','less-loader'],
},
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader','sass-loader'],
},
new MiniCssExtractPlugin()
指定输出文件目录
new MiniCssExtractPlugin({
filename:"css/main.css"
})
2.css兼容性处理
npm i postcss-loader postcss postcss-preset-env -D
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader',{
loader:"postcss-loader",
options:{
postcssOptions:{
plugins:[
"postcss-preset-env"
]
}
}
}],
},
在package.json中加入
"browserslist":[
"ie >= 8"
]
3.封装样式Loader函数
function GetStyleLoader(pre) {
return [
MiniCssExtractPlugin.loader, 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
4.css压缩
npm i css-minimizer-webpack-plugin –save-dev
new CssMinimizerPlugin()
5.sourceMap源代码映射
当我们在开发过程中,可能会出现错误,但是当我们在浏览器调试时会发现,报错的位置是打包后的位置,因此我们需要sourceMap定位源代码错误的位置,更方便开发
devtool: "eval-cheap-module-source-map" ///开发环境使用
devtool: "source-map" ///生成环境使用
6.提升打包速度
devServer: {
static: {
directory: path.join(__dirname, 'src'),
},
compress: true,
port: 9000,
hot:true
},
7.OneOf
每个文件只能被其中一个Loader(配置)处理
module: {
rules: [
{
oneOf:[
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
}
],
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
},
generator: {
//输出图片名字
filename: "images/[hash][ext]"
}
}
]
}
]
},
8.Include/Exclude
Exclude 排除,除了指定的都处理
Include 制定 处理制定的
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
}
],
},
9.Bable和Eslint的缓存
Bable
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true, //开启缓存
cacheCompression: false //关闭缓存文件压缩
/* presets: ["@babel/preset-env"] */
}
}
],
},
Eslint
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "src"),
exclude:/node_modules/,
cache:true,
cacheLocation:path.join(__dirname,'../node_modules/.cache/eslintcache')
}
),
10.多进程打包
npm i thread-loader -D
const os = require('os')
const threads = os.cpus().length
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader:'thread-loader',
options: {
works: threads,
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true, //开启缓存
cacheCompression: false //关闭缓存文件压缩
/* presets: ["@babel/preset-env"] */
}
}
],
},
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "src"),
exclude:"node_modules",
cache:true,
cacheLocation:path.join(__dirname,'../node_modules/.cache/eslintcache'),
threads,
}
),
压缩js
const TerserWebpackPlugin = require('terser-webpack-plugin')
new TerserWebpackPlugin({
parallel:threads
})
更改压缩插件的位置
optimization:{
//压缩的操作
minimizer:[
new CssMinimizerPlugin(), //压缩css
new TerserWebpackPlugin({ //压缩js
parallel:threads
})
]
},
mode: "development",
11.减少图片体积
npm i image-minimizer-webpack-plugin imagemin -D
无损压缩
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo –save-dev
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
module.exports = {
optimization: {
minimizer: [
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
],
},
};
12.进一步解决兼容性问题
coreJs npm i core.js
babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: [
[
"@babel/preset-env", // 预设名称
{
useBuiltIns: 'usage', // 选项
corejs: 3 // 选项
}
]
]
};
};
13.PWD
npm install workbox-webpack-plugin –save-dev
const WorkboxPlugin = require('workbox-webpack-plugin');
new WorkboxPlugin.GenerateSW({
// 这些选项帮助快速启用 ServiceWorkers
// 不允许遗留任何“旧的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
注册 Service Worker
npx SW registered
启动服务
npm i server -g
npx server dist
6.CodeSplit
1.CodeSplit
添加多入口
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
another: './src/another-module.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
const path = require('path');
module.exports = {
entry: './src/index.js',
mode: 'development',
entry: {
index: './src/index.js', //主入口
another: './src/another-module.js', //其他js文件
},
output: {
filename: 'main.js', //主入口打包的输出目录
filename: '[name].bundle.js', //其他js文件打包的输出目录
path: path.resolve(__dirname, 'dist'),
},
};
动态导入(Dynamic Imports)
通过模块的内联函数调用来分离代码。例如,使用import()
函数:
import(/* webpackChunkName: 'subPageA' */'./subPageA').then(function(res){
console.log('import()', res)
});
防止依赖重复
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: {
import: './src/index.js',
dependOn: 'shared',
},
another: {
import: './src/another-module.js',
dependOn: 'shared',
},
shared: 'lodash',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
runtimeChunk: 'single',
},
};
2.SplitChunksPlugin
const path = require('path');
module.exports = {
mode: 'development',
entry: {
index: './src/index.js',
another: './src/another-module.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
3.preload、prefetch
npm i –save-dev @vue/preload-webpack-plugin
const PreLoadWebpackPlugin = require('@vue/preload-webpack-plugin');
new PreLoadWebpackPlugin({
rel:"preload",
as:"script",
}),
/*new PreLoadWebpackPlugin({
rel:"prefetch",
as:"script",
}),*/
7.typeScript
npm install –save-dev typescript ts-loader
tsconfig.js
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react",
"allowJs": true,
"moduleResolution": "node",
}
}
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
8.react-cli
1.webpack.dev.js
基本配置
const path = require("path")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
function GetStyleLoader(pre) {
return [
MiniCssExtractPlugin.loader, 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/main.js",
output: {
path: undefined,
filename: "js/[name].bundle.js",
chunkFilename: "static/js/[name].chunk.js",
assetModuleFilename: "static/media/[hash:10][ext][query]"
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false
}
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
],
mode: "development",
devtool: "cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
}
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
}
}
.eslintrc.js
module.exports = {
extends: [
"react-app", //react
],
parserOptions: {
babelOptions:{
presets:[
["react-app",false],
"babel-preset-react-app/prod"
]
}
},
}
babel.config.js
module.exports = {
presets: ['react-app'],
};
npm i eslint-webpack-plugin html-webpack-plugin css-loader postcss-loader style-loader less-loader postcss-preset-env sass stylus-loader sass-loader -D
npm i -D babel-loader @babel/core babel-preset-react-app eslint-config-react-app -D
npm i webpack-dev-server webpack webpack-cli -D
npm i react react-dom
2.解决启动后报错的问题
Error: [BABEL] D:\MyTest\cli\src\index.js: Using `babel-preset-react-app` requires that you specify `NODE_ENV` or `BABEL_ENV` environment variables. Valid values are "development", "test", and "production". Instead, received: undefined. (While processing: "D:\\MyTest\\cli\\node_modules\\babel-preset-react-app\\index.js")
npm i –save-dev cross-env
设置启动脚本为 “serve”: “cross-env NODE_ENV=production webpack serve –config ./config/webpack.dev.js”,
//在webpack.config.js中配置
resolve: {
extensions: ['.js','.jsx','.json'],
},
3.更新局部代码
npm i -D @pmmmwh/react-refresh-webpack-plugin react-refresh
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
{
test: /\.jsx?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
plugins:[
'react-refresh/babel'
]
}
},
new ReactRefreshPlugin()
4.解决路由报错问题
在我们使用react-router-dom的时候会出现这样的问题
Cannot GET /about
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true //解决前端路由刷新404的问题
},
5.生产模式
const path = require("path")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
function GetStyleLoader(pre) {
return [
MiniCssExtractPlugin.loader, 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname,"../dist"),
filename: "js/[name].[contenthash:10].js",
chunkFilename: "static/js/[name].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]",
clean:true,
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
}
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
],
mode: "production",
devtool: "source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
resolve: {
extensions: ['.js','.jsx','.json'],
},
}
npm i css-minimizer-webpack-plugin mini-css-extract-plugin terser-webpack-plugin -D
6.图标的解析
npm i copy-webpack-plugin -D
const CopyWebpackPlugin = require('copy-webpack-plugin');
new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../public'),
to: path.resolve(__dirname,'../dist'),
globOptions:{
//忽略这个文件
ignore:["**/index.html"]
}
}
]
}),
7.合并配置
webpack.config.js
const path = require("path")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ReactRefreshPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const isproduction = process.env.NODE_ENV === "production"
function GetStyleLoader(pre) {
return [
isproduction?MiniCssExtractPlugin.loader:'style-loader', 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/index.js",
output: {
path: isproduction?path.resolve(__dirname,"../dist"):undefined,
filename: isproduction?"js/[name].[contenthash:10].js":"js/[name].bundle.js",
chunkFilename: isproduction?"static/js/[name].chunk.js":"static/js/[name].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]",
clean:true
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
plugins:[
!isproduction && 'react-refresh/babel'
].filter(Boolean)
}
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
!isproduction && new ReactRefreshPlugin(),
isproduction && new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
isproduction && new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../public'),
to: path.resolve(__dirname,'../dist'),
globOptions:{
//忽略这个文件
ignore:["**/index.html"]
}
}
]
}),
].filter(Boolean),
mode: isproduction?"production": "development",
devtool: isproduction?"source-map":"cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimize:isproduction,
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true //解决前端路由刷新404的问题
},
resolve: {
extensions: ['.js','.jsx','.json'],
},
}
8.优化
npm i antd
//webpack.config.js
function GetStyleLoader(pre) {
return [
isproduction?MiniCssExtractPlugin.loader:'style-loader', 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre && {
loader:pre,
options:pre === "less-loader"?{
//antdesign自定义主题色
lessOptions:{
modifyVars:{"@primary-color":"#1DA57A"},
javascriptEnabled:true
}
}:{}
}
].filter(Boolean)
}
分开打包cacheGroups
optimization: {
splitChunks: {
chunks: "all",
cacheGroups:{
react:{
test:/[\\/]node_modules[\\/]react(.*)?[\\/]/,
name:"chunk-react",
priority:40,
},
antd:{
test:/[\\/]node_modules[\\/]antd[\\/]/,
name:"chunk-antd",
priority:30,
},
libs:{
test:/[\\/]node_modules[\\/]/,
name:"chunk-libs",
priority:20,
}
}
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimize:isproduction,
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
module.exports = {
...
performance:false //关闭性能分析,提升打包效率
}
9.VueCli
1.vue-loader
npm install -D vue-loader vue-template-compiler
npm i eslint-webpack-plugin html-webpack-plugin vue-style-loader css-loader postcss-loader sass less-loader sass-loader stylus-loader babel-loader postcss-preset-env webpack webpack-cli webpack-dev-server cross-env -D
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
module: {
rules: [
// ... 其它规则
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// 请确保引入这个插件!
new VueLoaderPlugin()
]
}
.eslintrc.js
module.exports = {
root:true,
env:{
node:true
},
extends: [
"plugin:vue/vue3-essential","eslint:recommended"
],
parserOptions:{
parser:"@babel/eslint-parser",
}
}
babel.config.js
module.exports = {
presets: ['@vue/cli-plugin-babel/preset'],
};
npm i @babel/eslint-parser eslint-plugin-vue -D
2.给vue赋值全局变量
const {DefinePlugin} = require("webpack")
plugins: [
...
new DefinePlugin({
__VUE_OPTIONS_API__:true,
__VUE_PROD_DEVTOOLS__:false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false
})
],
3.整体开发模式下vue的配置
const path = require("path")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const {DefinePlugin} = require("webpack")
function GetStyleLoader(pre) {
return [
'vue-style-loader', 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/index.js",
output: {
path: undefined,
filename: "static/js/[name].bundle.js",
chunkFilename: "static/js/[name].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]"
},
module: {
rules: [
{
test: /\.js?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__:true,
__VUE_PROD_DEVTOOLS__:false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false
})
],
mode: "development",
devtool: "cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
}
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true //解决前端路由刷新404的问题
},
resolve: {
extensions: ['.js','.vue','.json'],
},
}
4.生产模式配置
const path = require("path")
const {DefinePlugin} = require("webpack")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
function GetStyleLoader(pre) {
return [
MiniCssExtractPlugin.loader, 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname,"../dist"),
filename: "static/js/[name].[contenthash:10].js",
chunkFilename: "static/js/[name].[contenthash:10].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]",
clean:true,
},
module: {
rules: [
{
test: /\.js?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../public'),
to: path.resolve(__dirname,'../dist'),
globOptions:{
//忽略这个文件
ignore:["**/index.html"]
}
}
]
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__:true,
__VUE_PROD_DEVTOOLS__:false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false
})
],
mode: "production",
devtool: "source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
resolve: {
extensions: ['.js','.vue','.json'],
},
}
npm i mini-css-extract-plugin css-minimizer-webpack-plugin terser-webpack-plugin copy-webpack-plugin html-webpack-plugin -D
5.合并配置
webpack.config.js
const path = require("path")
const {DefinePlugin} = require("webpack")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
const isproduction = process.env.NODE_ENV === "production"
function GetStyleLoader(pre) {
return [
isproduction ? MiniCssExtractPlugin.loader:"vue-style-loader", 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/index.js",
output: {
path: isproduction?path.resolve(__dirname,"../dist"):undefined,
filename: isproduction?"static/js/[name].[contenthash:10].js":"static/js/[name].js",
chunkFilename: isproduction?"static/js/[name].[contenthash:10].chunk.js":"static/js/[name].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]",
clean:true,
},
module: {
rules: [
{
test: /\.js?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
isproduction && new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
isproduction && new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../public'),
to: path.resolve(__dirname,'../dist'),
globOptions:{
//忽略这个文件
ignore:["**/index.html"]
}
}
].filter(Boolean)
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__:true,
__VUE_PROD_DEVTOOLS__:false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false
})
],
mode: isproduction ? "production":"development",
devtool: isproduction ?"source-map":"cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimize:isproduction,
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true //解决前端路由刷新404的问题
},
resolve: {
extensions: ['.js','.vue','.json'],
},
}
6.element-plus的使用
npm i element-plus
//全部引入
import { createApp } from 'vue'
import App from './App'
import router from './router';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const Vue = createApp(App)
Vue.use(router)
Vue.use(ElementPlus)
Vue.mount(document.getElementById("app"));
按需导入
npm install -D unplugin-vue-components unplugin-auto-import
npm i unplugin-vue-components@0.25.2 -D npm install unplugin-auto-import@0.16.1
// webpack.config.js
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
// ...
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}
按需导入的使用
<template>
<div class="about">AboutTitle
<el-button type="primary">click me</el-button>
</div>
</template>
<script>
import {ElButton} from 'element-plus'
export default{
name:"About",
componenets:{
ElButton
}
}
</script>
<style>
.about{
color: rgb(188, 14, 72);
}
</style>
7.使用路径别名
resolve: {
extensions: ['.js','.vue','.json'],
alias:{
"@":path.resolve(__dirname,"../src")
}
},
8.优化
splitChunks: {
chunks: "all",
cacheGroups:{
vue:{
test:/[\\/]node_modules[\\/]vue(.*)?[\\/]/,
name:"chunk-vue",
priority:40,
},
elementPlus:{
test:/[\\/]node_modules[\\/]element-plus[\\/]/,
name:"chunk-elementPlus",
priority:30,
},
libs:{
test:/[\\/]node_modules[\\/]/,
name:"chunk-libs",
priority:20,
}
}
},
module.exports = {
...
performance:false //关闭性能分析,提升打包效率
}
最后的完整配置
const path = require("path")
const {DefinePlugin} = require("webpack")
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
const isproduction = process.env.NODE_ENV === "production"
function GetStyleLoader(pre) {
return [
isproduction ? MiniCssExtractPlugin.loader:"vue-style-loader", 'css-loader', {
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env"
]
}
}
},
pre
].filter(Boolean)
}
module.exports = {
entry: "./src/main.js",
output: {
path: isproduction?path.resolve(__dirname,"../dist"):undefined,
filename: isproduction?"static/js/[name].[contenthash:10].js":"static/js/[name].js",
chunkFilename: isproduction?"static/js/[name].[contenthash:10].chunk.js":"static/js/[name].chunk.js",
assetModuleFilename : "static/media/[hash:10][ext][query]",
clean:true,
},
module: {
rules: [
{
test: /\.js?$/,
include: path.resolve(__dirname, "../src"),
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false,
}
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: GetStyleLoader(),
},
{
test: /\.less$/,
use: GetStyleLoader('less-loader'),
},
{
test: /\.s[ac]ss$/,
use: GetStyleLoader('sass-loader')
},
{
test: /\.(png|jpg|jpe?g|gif|webp|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024
}
}
},
{
test: /\.(woff2|ttf)/,
type: "asset/resource",
}
]
},
plugins: [
new ESLintWebpackPlugin(
{
context: path.resolve(__dirname, "../src"),
exclude: "node_modules",
cache: true,
cacheLocation: path.join(__dirname, '../node_modules/.cache/eslintcache'),
}
),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html")
}),
isproduction && new MiniCssExtractPlugin({
filename: "static/css/[name].[contenthash:10].css",
chunkFilename: "static/css/[name].[contenthash:10].chunk.css",
}),
isproduction && new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, '../public'),
to: path.resolve(__dirname,'../dist'),
globOptions:{
//忽略这个文件
ignore:["**/index.html"]
}
}
].filter(Boolean)
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__:true,
__VUE_PROD_DEVTOOLS__:false,
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__:false
}),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
mode: isproduction ? "production":"development",
devtool: isproduction ?"source-map":"cheap-module-source-map",
optimization: {
splitChunks: {
chunks: "all",
cacheGroups:{
vue:{
test:/[\\/]node_modules[\\/]vue(.*)?[\\/]/,
name:"chunk-vue",
priority:40,
},
elementPlus:{
test:/[\\/]node_modules[\\/]element-plus[\\/]/,
name:"chunk-elementPlus",
priority:30,
},
libs:{
test:/[\\/]node_modules[\\/]/,
name:"chunk-libs",
priority:20,
}
}
},
runtimeChunk:{
name: entrypoint => `runtime~${entrypoint.name}.js`,
},
minimize:isproduction,
minimizer:[new CssMinimizerPlugin(),new TerserWebpackPlugin({
test: /\.js(\?.*)?$/i,
})]
},
devServer:{
host:"localhost",
port:3000,
open:true,
hot:true,
historyApiFallback:true //解决前端路由刷新404的问题
},
resolve: {
extensions: ['.js','.vue','.json'],
alias:{
"@":path.resolve(__dirname,"../src")
}
},
performance:false
}
10.原理分析
1.构建Loader
npm i html-webpack-plugin webpack webpack-cli -D
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry:"./src/main.js",
output:{
path:path.resolve(__dirname,"./src"),
filename:"js/[name].js",
clean:true
},
module:{
rules:[
]
},
plugins:[
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "./public/index.html")
}),
],
mode:"development"
}
定义loader文件
//loaders/test-loaders.js
module.exports = function (content){
console.log(content)
return content
}
在rules中配置
//webpack.config.js
module:{
rules:[
{
test: /\.js$/,
loader:'./loaders/test-loader.js'
}
]
},
输出结果
let arr = [1,2,3,4] ===>该文件为mian.js中的文件
/*
// content 文件管理的内容
// map sourceMap
// meta 别的loader传递的数据
*/
module.exports = function (content,map,meta){
console.log(content,map,meta)
return content
}
2.同步loader
module.exports = function(content,map,meta){
/*
1 代表是否有错误
2 content 处理的内容
3 map 继续传递sourcemap
4 meta 给下一个loader传递参数
*/
this.callback(null,content,map,meta)
}
3.异步loader
module.exports = function(content,map,meta){
const callback = this.async();
setTimeout(()=>{
console.log("test2")
callback(null,content,map,meta)
},1000)
}
4.raw loader
//<Buffer 6c 65 74 20 61 72 72 20 3d 20 5b 31 2c 32 2c 33 2c 34 5d 0d 0a>'
//接收到的是Buffer数据内容
module.exports = function(content){
console.log(content)
return content
}
module.exports.raw = true;
5.pitch loader
优先执行pitch内的方法
module.exports = function(content){
return content
}
module.exports.pitch = function(){
console.log("pitch")
}
6.自定义loader
清除所有的console.log()语句
module.exports = function(content){
return content.replace(/console\.log\(.*\);?/g,"")
}
schema.json
{
"type":"object",
"properties":{
"author":{
"type":"string"
}
},
"additionalProperties":false //不能新增字段
}
banner-loader.js
const schema = require("./schema.json")
module.exports = function(conten){
const options = this.getOptions(schema)
const prefix = `
/*
Author:${options.author}
*/
`
return prefix + conten
}
webpack.config.js
{
test: /\.js$/,
loader:"./loaders/banner-loader.js",
options:{
"author":"RC"
}
},
7.file-loader
file-loader.js
const loaderUtils = require("loader-utils")
module.exports = function(content){
let interpolateName = loaderUtils.interpolateName(this,"[hash].[ext][query]",{
content:content
})
interpolateName =`images/${interpolateName}`
this.emitFile(interpolateName,content)
return `module.exports = "${interpolateName}"`
}
module.exports.raw = true
webpack.config.js
{
test: /\.(png|jpe?g|gif)$/,
loader: "./loaders/file-loader.js",
type:"javascript/auto"
},
8.style.lodaer
module.exports.pitch = function(remainingRequest){
const path = remainingRequest.split('!').map(absolutePath => {
return this.utils.contextify(this.context,absolutePath)
}).join('!')
const script =`
import style from "!!${path}"
const style1 = document.createElement('style')
style1.innerHTML = style
document.head.appendChild(style1)
`
//终止后面loader的执行
return script
}
11.plugin
1.自定义plugin
class TestPlugin{
constructor(){
console.log("this is constructor")
}
apply(compile){
console.log("compile")
}
}
module.exports = TestPlugin
2.hooks的创建
apply(compile){
console.log("compile")
compile.hooks.environment.tap("TestPlugin",()=>{
console.log(1)
})
compile.hooks.emit.tap("TestPlugin",()=>{
console.log(2)
})
compile.hooks.emit.tapAsync("TestPlugin",()=>{
setTimeout(()=>{
console.log(3)
},1000)
})
}
class TestPlugin {
constructor() {
console.log("this is constructor")
}
apply(compiler) {
console.log("compile")
compiler.hooks.environment.tap("TestPlugin", () => {
console.log(1)
})
compiler.hooks.emit.tap("TestPlugin", (compilation) => {
console.log(2)
})
compiler.hooks.emit.tapAsync("TestPlugin", (compilation,callback) => {
compilation.hooks.seal.tap("TestPlugin", () => {
console.log("Test")
})
setTimeout(() => {
console.log(3)
callback()
}, 1000)
})
}
}
3.在文件前添加注释的plugin
class BannerPlugin{
apply(compiler){
compiler.hooks.emit.tap("BannerPlugin",(compilation)=>{
//过滤图片资源,只保留js和css资源
const extension = ['js','css']
//过滤资源
const assets = Object.keys(compilation.assets).filter((path)=>{
let splitted = path.split('.')
const ext = splitted[splitted.length-1]
return extension.includes(ext)
})
//需要添加的注释前缀
let prefix = `/*
Author:"RC"
*/`
assets.forEach(asset=>{
//获取原来的内容
let source = compilation.assets[asset].source()
//更改文件内容
let content = prefix+=source
compilation.assets[asset] = {
//source就是文件的具体内容
source(){
return content
},
//资源大小
size(){
return content.length
}
}
})
})
}
}
module.exports = BannerPlugin
传递参数
new BannerPlugin({
"name":"wsRC"
})
constructor(options = {}){
this.options = options
}
4.clean-plugins
清空输出目录的资源
class CleanPlugin{
apply(compiler){
const outputPath = compiler.options.output.path
const fs = compiler.outputFileSystem
compiler.hooks.emit.tap("CleanPlugin",(compilation)=>{
this.removeFiles(fs,outputPath)
})
}
//删除文件
removeFiles(fs,output){
const files = fs.readdirSync(output)
files.forEach(file => {
let filepath = `${output}/${file}`
const fileStat = fs.statSync(filepath)
if (fileStat.isDirectory()){
//是文件夹
this.removeFiles(fs,filepath)
}else{
//是文件
fs.unlinkSync(filepath)
}
});
}
}
module.exports = CleanPlugin
5.AnalyzeWebpackPlugin
分析包的大小
class AnalyzePlugin{
apply(compiler){
compiler.hooks.emit.tap("AnalyzePlugin",(compilation)=>{
const assets = Object.entries(compilation.assets)
let content = `| 名称 | 大小 |
| --- | --- |`
assets.forEach(([filename,file])=>{
content+=`\n| ${filename} | ${Math.ceil(file.size() / 1024)}kb |`
})
compilation.assets["analyze.md"] = {
source(){
return content
},
size(){
return content.length
}
}
})
}
}
module.exports = AnalyzePlugin
6.inlinePlugin
将runtime文件内联到html文件
const HtmlWebpackPlugin = require("safe-require")("html-webpack-plugin")
class InlinePlugin{
apply(compiler){
compiler.hooks.compilation.tap("InlinePlugin",(compilation)=>{
const hooks = HtmlWebpackPlugin.getHooks(compilation)
/*
{
tagName: 'script',
voidTag: false,
meta: { plugin: 'html-webpack-plugin' },
attributes: { defer: true, src: 'js/main.js' }
}
*/
hooks.alterAssetTagGroups.tap(
"InlinePlugin",(assets)=>{
assets.headTags = this.getInlineChunk(assets.headTags,compilation.assets)
assets.bodyTags = this.getInlineChunk(assets.bodyTags,compilation.assets)
}
)
})
}
getInlineChunk(tags,assets){
return tags.map((tag)=>{
if (tag.tagName != "script") return tag
const filepath = tag.attributes.src
if (!filepath) return tag
if (!/runtime(.*)\.js$/g.test(filepath)) return tag
return {
tagName: 'script',
innerHTML: assets[filepath].source(),
closeTag:true
}
})
}
}
module.exports = InlinePlugin