插件(plugin) loader用来转换文件,插件用来执行更广泛的任务。包括:打包优化、资源管理,注入环境变量。 使用一个插件,只需要require()它,添加到plugins数组中,多数插件可以通过option选项自定义。 你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例
webpack插件是一个具有apply方法的js对象,apply 方法会被 webpack compiler 调用,并且在__整个__编译生命周期都可以访问 compiler 对象。
1 2 3 4 5 6 const HtmlWebpackPlugin = require ('html-webpack-plugin' ); module .exports = { plugins:[ new HtmlWebpackPlugin({ template : './src/index.html' }); ] }
HtmlWebpackPlugin插件为应用程序生成一个html文件,并自动注入所以生成的bundle
clean-webpack-plugin:打包之前删除 dist。
1 2 3 4 5 const { CleanWebpackPlugin } = require ('clean-webpack-plugin' );plugins:[ new CleanWebpackPlugin(); ]
CommonsChunkPlugin:提取chunks间共享的通用模块
MiniCssExtractPlugin:为每个引入css的js文件创建一个css文件
HotModuleReplacementPlugin:启用模块热更替
uglifyjs-webpack-plugin:压缩js文件的体积
为什么使用webpack?
框架、ES6模块化语法,预处理器scss等需要转换为浏览器能识别的js、css等
webpack静态打包工具, 处理非js文件
功能:
开发模式-development:仅能编译JS中的ES6模块化语法 生产模式-production:能编译JS中的ES6模块化语法,还能压缩js代码
安装依赖:
1 2 npm init -y npm i webpack webpack-cli -D
webpack编译:
1 npx webpack ./src/main.js --mode=development
核心概念:
entry:入口,指定webpack从哪个文件开始打包 output: 输出,打包完的代码输出到哪里如何命名等 loader:加载器,webpack本身只能处理js、json等资源,其他资源需要借助loader,webpack才能解析 plugins:插件,扩展webpack的功能 mode:模式,开发:development, 生产production
webpack配置文件webpack.config.js
根目录下创建webpack.config.js文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const path = require ('path' )module .exports = { entry: './src/main.js' , output: { path: path.resolve(__dirname, 'dist' ), filename: 'main.js' }, module : { rules: [] }, plugins: [], mode: 'development' }
运行打包:
开发模式: 1、编译代码,使浏览器能识别:样式资源、字体图标、图片、html等) 2、代码质量检查,eslint等
处理css资源:css-loader
安装css-loader:
1 npm install --save-dev css-loader style-loader
配置loader:
在 webpack 的配置中,loader 有两个属性:
test 属性,识别出哪些文件会被转换。
use 属性,定义出在进行转换时,应该使用哪个 loader。
1 2 3 4 5 6 7 8 9 10 11 12 module .exports = { module : { rules: [ { test: /\.css$/ , use: [ 'style-loader' , 'css-loader' ]} ] }, }
使用less-loader:
首先,你需要先安装 less 和 less-loader:
1 npm install less less-loader --save-dev
然后将该 loader 添加到 webpack 的配置中去:
1 2 3 4 5 6 7 8 9 10 11 12 13 module .exports = { module : { rules: [ { test: /\.less$/ , use: [ 'style-loader' , 'css-loader' , 'less-loader' ]} ] }, }
使用sass-loader 首先,你需要安装 sass-loader:
1 npm install sass-loader sass webpack --save-dev
然后将本 loader 添加到你的 Webpack 配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 module .exports = { module : { rules: [ { test: /\.s[ac]ss$/i , use: [ 'style-loader' , 'css-loader' , 'sass-loader' , ], }, ], }, }
使用stylus-loader,首先,先安装stylus和stylus-loader:
1 npm install stylus stylus-loader --save-dev
将stylus-loader添加到配置中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 module .exports = { module : { rules: [ { test: /\.styl$/ , use: [ 'style-loader' , 'css-loader' , 'stylus-loader' , ], }, ] } }
处理图片资源,webpack4处理图片资源使用file-loader和url-loader,现在webpack5,使用资源模块类型(asset module type),通过添加 4 种新的模块类型,来替换所有这些 loader:
asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 module .exports = { module : { rules: [ { test: /\.(png|jpg|webp|svg|jpeg)$/ , type: 'asset' , parser: { dataUrlCondition: { maxSize: 10 * 1024 } } }, ] } }
将文件输出到指定资源目录:
1 2 3 4 5 6 7 8 9 10 11 12 13 { test: /\.(png|jpg|webp|svg|jpeg)$/ , type: 'asset' , parser: { dataUrlCondition: { maxSize: 10 * 1024 } }, generator: { filename: 'static/images/[hash][ext][query]' } },
[hash:10]代表哈希值取10位
每次构建前清理dist文件夹:
1 2 3 4 5 6 7 8 module .exports = { output: { path: path.resolve(__dirname, 'dist' ), filename: 'main.js' , clean: true }, }
使用字体资源:
1 2 3 4 5 6 7 { test: /\.(ttf|woff|woff2)$/ , type: 'asset/resource' , generator: { filename: 'static/media/[hash][ext][query]' } }
其他资源比如map3等也可以像字体资源处理
处理js资源: 针对js兼容性处理,使用babel完成 针对代码个格式,使用eslint处理
Eslint配置文件写法:
eslint在webpack4是eslint-loader,在webpack5是plugins
使用eslint需要安装 eslint-webpack-plugin:
1 npm install eslint-webpack-plugin --save-dev
注意: 如果未安装 eslint >= 7 ,你还需先通过 npm 安装:
1 npm install eslint --save-dev
然后把插件添加到你的 webpack 配置:
1 2 3 4 5 6 7 8 9 10 11 12 const ESLintPlugin = require ('eslint-webpack-plugin' );module .exports = { plugins: [ new ESLintPlugin({ context: path.resolve(__dirname, 'src' ) }) ], };
创建eslint配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 module .exports = { extends : ['eslint:recommended' ], env: { node: true , browser: true }, parserOptions: { ecmaVersion: 6 , sourceType: "module" }, rules: { "no-var" : 2 } }
Babel将es6语法编写的代码转换为向后兼容的js语法,能够运行在当前和旧版本的浏览器或其他环境中。
配置文件有多种写法:
babel.config.*: 新建文件,位于根目录
babel.config.js
babel.config.json
.babelrc.*:新建文件,位于根目录
.babelrc
.babelrc.js
.babelrc.json
package.json中的label中,不需要创建文件
使用babel,先安装:
1 npm install -D babel-loader @babel/core @babel/preset-env webpack
webpack 配置对象中,需要将 babel-loader 添加到 module 列表中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 module : { rules: [ { test: /\.m?js$/ , exclude: /(node_modules|bower_components)/ , use: { loader: 'babel-loader' , options: { presets: ['@babel/preset-env' ] } } } ] }
HtmlWebpackPlugin 简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。这对于那些文件名中包含哈希值,并且哈希值会随着每次编译而改变的 webpack 包特别有用。
安装:
1 npm install --save-dev html-webpack-plugin
该插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle.
1 2 3 4 5 module .exports = { plugins: [ new HtmlWebpackPlugin() ] }
webpack-dev-server监听文件改变,自动打包
1 npm i webpack-dev-server -D
配置webpack.config.js:
1 2 3 4 5 6 7 8 module .exports = { devServer: { host: "localhost" , port: 3000 , open: true } }
运行命令:npx webpack serve
生产模式:
优化代码运行性能 优化打包速度
根目录下创建config目录,创建webpack.dev.js和webpack.prod.js
然后运行:
1 2 npx webpack serve --config ./config/webpack.dev.js // dev npx webpack --config ./config/webpack.prod.js // prod
或者加入package.json:
1 2 3 4 5 "scripts": { "start": "npm run dev", "dev": "webpack serve --config ./config/webpack.dev.js", "build": "webpack --config ./config/webpack.prod.js" }
css处理,提取css文件.
css文件目前被打包到js文件,当js文件加载时,会创建一个style标签来生成样式
这样对网站不好,会出现闪屏
单独将css文件分离,用link标签加载性能更好
安装:
1 npm install --save-dev mini-css-extract-plugin
建议 mini-css-extract-plugin 与 css-loader 一起使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 const MiniCssExtractPlugin = require ("mini-css-extract-plugin" );module .exports = { plugins: [new MiniCssExtractPlugin()], module : { rules: [ { test: /\.css$/i , use: [MiniCssExtractPlugin.loader, "css-loader" ], }, ], }, };
运行npm run build
打包后的index.html会link引入css文件 不要同时使用 style-loader 与 mini-css-extract-plugin。
css样式兼容性处理. 需要安装 postcss-loader 和 postcss, postcss-preset-env
1 npm install --save-dev postcss-loader postcss postcss-preset-env
配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 module .exports = { module : { rules: [ { test: /\.css$/i , use: [ 'style-loader' , 'css-loader' , { loader: 'postcss-loader' , options: { postcssOptions: { plugins: [ [ 'postcss-preset-env' , { }, ], ], }, }, }, ], }, ], }, };
或者使用postcss本身的配置文件postcss.config.js:
1 2 3 4 5 6 7 8 9 10 module .exports = { plugins: [ [ 'postcss-preset-env' , { }, ], ], };
在package.json中配置需要浏览器兼容的程度:
1 2 3 4 5 "browserslist": [ "> 1%", "last 2 versions", "not ie <= 8" ]
比如display:flex,打包编译会变成
1 2 display : -webkit-box ;display : -ms-flexbox ;
优化和压缩css:
你需要安装 css-minimizer-webpack-plugin:
1 npm install css-minimizer-webpack-plugin --save-dev
接着在 webpack 配置中加入该插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const MiniCssExtractPlugin = require ("mini-css-extract-plugin" );const CssMinimizerPlugin = require ("css-minimizer-webpack-plugin" );module .exports = { module : { rules: [ { test: /.s?css$/ , use: [MiniCssExtractPlugin.loader, "css-loader" , "sass-loader" ], }, ], }, optimization: { minimizer: [ new CssMinimizerPlugin(), ], }, plugins: [new MiniCssExtractPlugin()], };
这将仅在生产环境开启 CSS 优化。
如果还想在开发环境下启用 CSS 优化,请将 optimization.minimize 设置为 true:
1 2 3 4 5 6 module .exports = { optimization: { minimize: true , }, };
默认生产模式已开启html压缩和js压缩
SourceMap: 开发环境中,运行代码source是编译过的。 sourcemap是源代码和编译后的代码的映射文件,代码出错后找到源代码出错位置,从而让浏览器提示出错误。
devtool选项配置sourcemap,不同的值会明显影响到构建(build)和重新构建(rebuild)的速度。 值有很多种,但是一般只关心开发和生产模式的值:
开发模式:devtool: cheap-module-source-map 优点:打包编译速度快,只包含行映射 缺点:没有列映射
生产模式:devtool: source-map 优点:包含行和列映射 缺点:打包编译速度更慢
启用 HMR: 提升打包构建速度。
开发时更改一个模块的代码,webpack会默认所有模块全部打包编译,速度很慢。 HotModuleReplacement:HMR热模块替换,在程序运行中添加、替换、删除模块而无需重新加载整个页面
1 2 3 4 5 6 module .exports = { devServer: { hot: true , }, };
但是hot: true不支持js热模块替换,js更改整个页面都重新刷新
实际使用框架,vue-loader、react-hot-loader解决热更替
oneOf: 每个文件只能被一个loader配置处理.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 module : { rules: [ { oneOf: [ { test: /\.css$/ , use: [ 'style-loader' , 'css-loader' , 'less-loader' ] }, { test: /\.less$/ , use: [ 'style-loader' , 'css-loader' , 'less-loader' , ], }, { test: /\.s[ac]ss$/ , use: [ 'style-loader' , 'css-loader' , 'sass-loader' , ], }, { test: /\.styl$/ , use: [ 'style-loader' , 'css-loader' , 'stylus-loader' , ], }, { test: /\.(png|jpg|webp|svg|jpeg)$/ , type: 'asset' , parser: { dataUrlCondition: { maxSize: 10 * 1024 } }, generator: { filename: 'static/images/[hash][ext][query]' } }, { test: /\.(ttf|woff|woff2)$/ , type: 'asset/resource' , generator: { filename: 'static/media/[hash][ext][query]' } }, { test: /\.js$/ , exclude: /node_modules/ , loader: 'babel-loader' } ] } ] },
Include/Exclude.
Include: 包含,只处理xxx文件 Exclude: 排除,除列xxx文件都处理
1 2 3 4 5 6 { test: /\.js$/ , exclude: /node_modules/ , loader: 'babel-loader' }
Cache: 开启缓存。
每次打包都要经过babel编译和eslint检查,速度慢 可以缓存之前的babel编译和eslint检查,这样第二次打包速度会更快
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 module : { rules: [ { test: /\.js$/ , exclude: /node_modules/ , loader: 'babel-loader' , options: { cacheDirectory: true , cacheCompression: false } } ] }, plugins: [ new EslintPlugin({ context: path.resolve(__dirname, '../src' ), exclude: "node_modules" , cache: true , cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslint-webpack-plugin/.eslintcache' ) }), ]
Thread-loader: 多进程。
项目越来越大时,打包速度更慢,可以开启多进程同时处理js文件。
使用时,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。
每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右。同时会限制跨进程的数据交换。
请仅在耗时的操作中使用此 loader! 安装:
1 npm install --save-dev thread-loader
使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 module .exports = { module : { rules: [ { test: /\.js$/ , include: path.resolve('src' ), use: [ "thread-loader" , ], }, ], }, }; use: [ { loader: "thread-loader" , options: { workers: 2 , workerParallelJobs: 50 , workerNodeArgs: ['--max-old-space-size=1024' ], poolRespawn: false , poolTimeout: 2000 , poolParallelJobs: 50 , name: "my-pool" }, }, ];
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const threads = os.cpus().length module : { rules: [ { test: /\.js$/ , exclude: /node_modules/ , use: [ { loader: 'thread-loader' , options: { works: threads } }, { loader: 'babel-loader' , options: { cacheDirectory: true , cacheCompression: false } } ] } ] }, plugins: [ new EslintPlugin({ context: path.resolve(__dirname, '../src' ), exclude: "node_modules" , cache: true , cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslint-webpack-plugin/.eslintcache' ), threads }), ]
TerserWebpackPlugin:该插件使用 terser 来压缩 JavaScript。 webpack v5 开箱即带有最新版本的 terser-webpack-plugin。如果你使用的是 webpack v5 或更高版本,同时希望自定义配置,那么仍需要安装 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本
1 npm install terser-webpack-plugin --save-dev
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const TerserPlugin = require ("terser-webpack-plugin" );module .exports = { optimization: { minimizer: [ new CssMinimizerPlugin(), new TerserPlugin({ parallel: threads }) ], }, };
减少代码体积: tree shaking.
开发时定义了一些工具函数库,或引入第三方工具函数库或组件库
可能只使用极小一部分功能确需要引入整个库,打包进来体积很大
Tree shaking一个术语,用于描述移除js中未使用的代码
webpack默认开启这个功能
减少babel代码体积:@babel/plugin-transform-runtime
安装:
1 npm install @babel/plugin-transform-runtime -D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 { test: /\.js$/ , exclude: /node_modules/ , use: [ { loader: 'thread-loader' , options: { works: threads } }, { loader: 'babel-loader' , options: { cacheDirectory: true , cacheCompression: false , plugins: ["@babel/plugin-transform-runtime" ] } } ] }
Image minimizer: 图片压缩。
本地静态图片压缩,减少代码体积
1 npm install image-minimizer-webpack-plugin --save-dev
无损压缩模式,需要安装:
1 npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo imagemin --save-dev
有损压缩:
1 npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo imagemin --save-dev
配置webpack.config.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const ImageMinimizerPlugin = require ("image-minimizer-webpack-plugin" );const { extendDefaultPlugins } = require ("svgo" );new ImageMinimizerPlugin({ minimizer: { implementation: ImageMinimizerPlugin.imageminGenerate, options: { plugins: [ ["gifsicle" , { interlaced : true }], ["jpegtran" , { progressive : true }], ["optipng" , { optimizationLevel : 5 }], [ "svgo" , { plugins: [ "preset-default" , "prefixIds" ], }, ], ], } }, }),
Code Split:代码分割。 打包代码时会将所有js文件打包到一个文件中,体积太大了,如果渲染首页,就应该只加载首页的js。
对js文件进行分割,渲染哪个页面就加载对应js,加载资源少速度更快
代码分割: 1、分割文件,将打包生成的文件进行分割,分为多个js文件 2、按需加载,需要哪个文件加载哪个
配置:optimization.splitChunks
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 module .exports = { optimization: { splitChunks: { chunks: 'async' , minSize: 20000 , minRemainingSize: 0 , minChunks: 1 , maxAsyncRequests: 30 , maxInitialRequests: 30 , enforceSizeThreshold: 50000 , cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/ , priority: -10 , reuseExistingChunk: true , }, default : { minChunks: 2 , priority: -20 , reuseExistingChunk: true , }, }, }, }, };
自定义loader:
clean-log-loader
1 2 3 4 5 module .exports = function (context ) { return context.replace(/console\.log\(.*\);?/g , "" ) }
使用:
1 2 3 4 { test: /\.js$/ , use: ['./loaders/clean-log-loader' ] }
loader分为:
pre 前置loader
normal 普通loader
inline 内联loader
post 后置loader
优先级:前置loader > 普通loader > 内联loader > 后置loader
同步loader:
1 2 3 module .exports = function (context ) { return context }
异步loader:
1 2 3 4 5 6 7 module .exports = function (content, map, meta ) { var callback = this .async(); someAsyncOperation(content, function (err, result ) { if (err) return callback(err); callback(null , result, map, meta); }); };
“Raw” Loader:默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 raw 为 true,loader 可以接收原始的 Buffer
1 2 3 4 5 6 7 module .exports = function (content ) { assert(content instanceof Buffer); return someSyncOperation(content); }; module .exports.raw = true ;
Pitching Loader:loader 总是 从右到左被调用。有些情况下,loader 只关心 request 后面的 元数据(metadata),并且忽略前一个 loader 的结果。在实际(从右到左)执行 loader 之前,会先 从左到右 调用 loader 上的 pitch 方法。
1 2 3 4 5 6 7 module .exports = function (content ) { return someSyncOperation(content, this .data.value); }; module .exports.pitch = function (remainingRequest, precedingRequest, data ) { data.value = 42 ; };
plugin: 自定义plugin。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class TestPlugin { constructor ( ) { console .log('testPlugin constructor' ) } apply (complier) { console .log('testPlugin apply' ) } } module .exports = TestPluginconst TestPlugin = require ('../plugins/test-plugin' ) plugins: [ new TestPlugin() ]
complier模块是webpack的主要引擎,通过cli或者node api传递的所有选项创建一个compilation 实例。 它扩展(extends)自 Tapable 类,用来注册和调用插件。大多数面向用户的插件会首先在 Compiler 上注册。
根据使用不同的钩子(hooks)和tap方法,插件可以以不同的方式运行。
同步tap
1 2 3 compiler.hooks.compile.tap('MyPlugin' , (params ) => { console .log('以同步方式触及 compile 钩子。' ); });
对于可以使用 AsyncHook 的 run 阶段, 则需使用 tapAsync 或 tapPromise(以及 tap)方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 compiler.hooks.run.tapAsync( 'MyPluginName' , (source, target, routesList, callback) => { console .log('以异步方式触及运行钩子。' ); callback(); } ); compiler.hooks.run.tapPromise('MyPluginName' , (source, target, routesList ) => { return new Promise ((resolve ) => setTimeout (resolve, 1000 )).then(() => { console .log('以异步的方式触发具有延迟操作的钩子。' ); }); }); compiler.hooks.run.tapPromise( 'MyPluginName' , async (source, target, routesList) => { await new Promise ((resolve ) => setTimeout (resolve, 1000 )); console .log('以异步的方式触发具有延迟操作的钩子。' ); } );
Compilation 模块会被 Compiler 用来创建新的 compilation 对象(或新的 build 对象)。 compilation 实例能够访问所有的模块和它们的依赖(大部分是循环依赖)。 它会对应用程序的依赖图中所有模块, 进行字面上的编译(literal compilation)。 在编译阶段,模块会被加载(load)、封存(seal)、优化(optimize)、 分块(chunk)、哈希(hash)和重新创建(restore)。
添加注释插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 const path = require ('path' )const os = require ('os' )const EslintPlugin = require ('eslint-webpack-plugin' )const HtmlWebpackPlugin = require ('html-webpack-plugin' )const MiniCssExtractPlugin = require ("mini-css-extract-plugin" )const CssMinimizerPlugin = require ('css-minimizer-webpack-plugin' )const TerserPlugin = require ("terser-webpack-plugin" )const ImageMinimizerPlugin = require ("image-minimizer-webpack-plugin" )const BannerWebpackPlugin = require ('../plugins/banner-webpack' )const threads = os.cpus().length function getStyleLoader (loader ) { return [ MiniCssExtractPlugin.loader, 'css-loader' , { loader: 'postcss-loader' , options: { postcssOptions: { plugins: [ [ 'postcss-preset-env' ], ], }, }, }, loader ].filter(Boolean ) } module .exports = { entry: './src/main.js' , output: { path: path.resolve(__dirname, '../dist' ), filename: 'static/js/main.js' , clean: true }, module : { rules: [ { oneOf: [ { test: /\.css$/ , use: getStyleLoader() }, { test: /\.less$/ , use: getStyleLoader('less-loader' ) }, { test: /\.s[ac]ss$/ , use: getStyleLoader('sass-loader' ) }, { test: /\.styl$/ , use: getStyleLoader('stylus-loader' ) }, { test: /\.(png|jpg|webp|svg|jpeg)$/ , type: 'asset' , parser: { dataUrlCondition: { maxSize: 10 * 1024 } }, generator: { filename: 'static/images/[hash][ext][query]' } }, { test: /\.(ttf|woff|woff2)$/ , type: 'asset/resource' , generator: { filename: 'static/media/[hash][ext][query]' } }, { test: /\.js$/ , exclude: /node_modules/ , use: [ { loader: 'thread-loader' , options: { works: threads } }, { loader: 'babel-loader' , options: { cacheDirectory: true , cacheCompression: false , plugins: ["@babel/plugin-transform-runtime" ] } } ] }, ] } ], }, optimization: { minimizer: [ new CssMinimizerPlugin(), new TerserPlugin({ parallel: threads }) ], }, plugins: [ new BannerWebpackPlugin({ author: 'zjy' }), new EslintPlugin({ context: path.resolve(__dirname, '../src' ), exclude: "node_modules" , cache: true , cacheLocation: path.resolve(__dirname, '../node_modules/.cache/eslint-webpack-plugin/.eslintcache' ), threads }), new HtmlWebpackPlugin({ template: path.resolve(__dirname, '../public/index.html' ) }), new MiniCssExtractPlugin({ filename: "static/css/main.css" }), new ImageMinimizerPlugin({ minimizer: { implementation: ImageMinimizerPlugin.imageminGenerate, options: { plugins: [ ["gifsicle" , { interlaced : true }], ["jpegtran" , { progressive : true }], ["optipng" , { optimizationLevel : 5 }], [ "svgo" , { plugins: [ "preset-default" , "prefixIds" ], }, ], ], } }, }) ], mode: 'production' , devtool: 'source-map' } new BannerWebpackPlugin({ author: 'zjy' }),