package.json
"scripts": {
"dev": "npx webpack serve --progress=profile --node-env development --config build/webpack.dev.js",
"build": "npx webpack build --progress=profile --node-env production --config build/webpack.prod.js"
},
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"babel-loader": "^9.1.3",
"babel-plugin-component": "^1.1.1",
"copy-webpack-plugin": "^9.1.0",
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^4.0.0",
"express": "^4.18.2",
"html-webpack-plugin": "^5.5.3",
"less": "^4.2.0",
"less-loader": "^11.1.3",
"mini-css-extract-plugin": "^2.7.6",
"postcss": "^8.4.31",
"postcss-loader": "^7.3.3",
"postcss-preset-env": "^9.3.0",
"progress-bar-webpack-plugin": "^2.1.0",
"style-loader": "^3.3.3",
"terser-webpack-plugin": "^5.3.9",
"vue-loader": "^15.11.1",
"vue-template-compiler": "^2.7.15",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-middleware": "^6.1.1",
"webpack-dev-server": "^4.15.1",
"webpack-merge": "^5.10.0"
},
"dependencies": {
"element-ui": "^2.15.14",
"vue": "^2.7.15"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
webpack.common.js
const path = require('path');
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 CopyWebpackPlugin = require("copy-webpack-plugin");
const webpack = require("webpack");
const { VueLoaderPlugin } = require('vue-loader');
const chalk = require('chalk');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
// 根目录
const root = path.resolve(__dirname, '..');
/**
* 以根目录拼接路径
* @param {...any} args
* @return
*/
function rootResolve(...args){
return path.resolve(root, ...args);
}
const devMode = process.env.NODE_ENV === 'development';
module.exports = {
resolve: {
extensions: [".js", ".jsx", ".json", ".vue"], // 可省略后缀
alias: {
'@': rootResolve('src')
}
},
entry: {
main: rootResolve('src/main.js')
},
output: {
filename: 'js/[name].[contenthash].js',
path: rootResolve('dist'),
clean: true,
publicPath: devMode ? '/' : './'
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.less$/i,
use: [
// 'style-loader',
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',
}
},
'css-loader',
'postcss-loader',
'less-loader',
],
},
{
test: /\.css$/i,
use: [
// 'style-loader', // 将 CSS 生成 style 标签插入 HTML 中
{
loader: MiniCssExtractPlugin.loader, //抽离css的loader
options: {
publicPath: '../', // css抽离后路径发生变化
}
},
'css-loader',
'postcss-loader'
],
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
generator:{
filename:'image/[name].[contenthash][ext]'
},
parser:{
dataUrlCondition: {
maxSize: 20*1024 // 操过20kb就使用图片资源,小于20kb就使用base64编码
}
}
}
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack',
template: rootResolve("public/index.html"), // 指定html模板文件
inject: 'body',
// hash: true, // 在引入JS时增加hash后缀字符串,去除缓存 bundle.js?a251...2ce5
filename: 'index.html',
chunks: ['main'], //配置html需要引入的chunk,index 是 entry中的key
minify: {
removeComments: true, // 移除注释
// removeAttributeQuotes: true, // 移除属性中的双引号
collapseWhitespace: true, // 去除空格与换行
}
}),
new MiniCssExtractPlugin({
filename: devMode ? 'style/[name].css' : 'style/[name].[contenthash].css',
// ignoreOrder: false, //启用关闭 警告⚠️
// chunkFilename: `style/[name].[chunkhash:8].css`
}),
new CopyWebpackPlugin({
patterns: [
{
from: rootResolve('public'),
to: rootResolve('dist'),
globOptions: {
ignore: ['**/*.html'] // 忽略不需要复制的文件
}
},
],
}),
new webpack.DefinePlugin({
BASE_URL: '1111',
// 'process.env': {
// NODE_ENV: JSON.stringify('production')
// }
}),
new VueLoaderPlugin(),
new ProgressBarPlugin({
format: `:msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`,
clear: false
}),
],
optimization: {
// usedExports: true, // 开发模式使用treesharking
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin()
],
// runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
moduleIds: 'deterministic',
},
performance: {
hints: devMode ? false : 'warning',
// 入口起点的最大体积 整数类型(以字节为单位)
maxEntrypointSize: 2000000, // 1kb=1024个字节=8比特
// 生成文件的最大体积 整数类型(以字节为单位 300k)
maxAssetSize: 1000000,
// 只给出 js/css 文件的性能提示
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
};
webpack.dev.js
const path = require('path');
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-cheap-module-source-map',
devServer: {
compress: true,
host: '0.0.0.0', // 【127.0.0.1 不能使用本机IP】【10.15.45.110 不能使用localhost】【0.0.0.0 两者皆可localhsot,10.15.45.110】
port: 8080,
// open: true,
static: {
directory: path.resolve(__dirname, '..', 'dist'),
},
hot: true,
// overlay: true, // 错误时在浏览器上全屏覆盖
},
});
webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
cache: {
type: 'filesystem',
compression: 'gzip',
},
});