webpack.config.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 PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
const ESLintPlugin = require('eslint-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const { VueLoaderPlugin } = require('vue-loader');
const { DefinePlugin } = require('webpack');
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
const workers = require('os').cpus().length;
const isDevelopment = process.env.NODE_ENV !== 'production';
module.exports = {
entry: {
main: "./src/main.ts",
},
output: {
path: path.resolve(__dirname, './dist'),
filename: "js/[contenthash:10]-[name].js",
chunkFilename: 'js/[chunkhash:10].js',
// assetModuleFilename:"public/media/[hash:10][ext]",
clean: true,
},
mode: process.env.NODE_ENV,
devServer: {
port: 8080,
hot: true,
// open: true,
historyApiFallback: true,
proxy: {}
},
plugins: [
new htmlWebpackPlugin({
template: "./src/index.html"
}),
!isDevelopment && new MiniCssExtractPlugin({
filename: 'css/[contenthash:10]-[name].css',
chunkFilename: '[chunkhash].css',
}),
new ESLintPlugin({
exclude: "node_modules",
context: path.resolve(__dirname, './src'),
cache: true,
cacheLocation: path.resolve(__dirname, "./node_modules/.cache/eslintcache")
}),
new VueLoaderPlugin(),
new DefinePlugin({
__VUE_OPTIONS_API__: true,
__VUE_PROD_DEVTOOLS__: false
}),
AutoImport({
resolvers: [ElementPlusResolver({
importStyle: "sass"
})],
}),
Components({
resolvers: [ElementPlusResolver({
importStyle: "sass"
})],
}),
// !isDevelopment && new CopyPlugin({
// patterns: [
// { from: "./src/favicon.ico", to: "./favicon.ico" },
// ],
// }),
].filter(Boolean),
optimization: {
minimize: isDevelopment ? false : true,
minimizer: [
new CssMinimizerPlugin(),
// new TerserPlugin({
// parallel: workers, //启用多进程打包
// })
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vue: {
test: /[\\/]node_modules[\\/]vue(.*)?[\\/]/,
name: "vue-chunk",
priority: 40,
},
ElementPlus: {
test: /[\\/]node_modules[\\/]element-plus(.*)?[\\/]/,
name: "ElementPlus-chunk",
priority: 30,
},
libs: {
test: /[\\/]node_modules[\\/]/,
name: "libs-chunk",
priority: 20,
}
}
},
},
resolve: {
extensions: [".vue", ".ts", ".js"],
extensionAlias: {
"@": path.resolve(__dirname, "src"),
}
},
devtool: isDevelopment ? "cheap-module-source-map" : "source-map",//生成map文件用于定位错误
performance: false,
module: {
rules: [
{
test: /\.vue$/i,
loader: "vue-loader",
options: {// 设置缓存
cacheDirectory: path.resolve(__dirname, '../node_modules/.cache/vue-loader')
}
},
{
test: /\.css$/i,
use: [...CssProcess()]
},
{
test: /\.less$/i,
use: [...CssProcess("less-loader")],
},
{
test: /\.s[ac]ss$/i,
use: [...CssProcess("sass-loader")],
},
{
test: /.(png|jpe?g|gif|webp)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 10 * 1024//小于10kb将图片转换为base64,减少请求数量
}
},
generator: {
filename: 'public/imgs/[contenthash:10]-[name][ext]'
}
},
{
test: /\.html$/i,
loader: "html-loader"
},
{
test: /\.(eot|ttf|woff|woff2|svg|mp3|mp4|avi)$/,
type: "asset/resource",
generator: {
filename: "public/media"
}
},
{
test: /\.([cm]?ts|js)$/,
exclude: /(node_modules|bower_components)/,
use: [
// {
// loader: "thread-loader",
// options: {
// workers,
// workerParallelJobs: 50,
// workerNodeArgs: ['--max-old-space-size=1024'],
// poolRespawn: false,
// poolTimeout: 2000,
// poolParallelJobs: 200,
// name: "my-pool"
// },
// },
{
loader: 'babel-loader',
options: {
cacheDirectory: true, // 开启缓存
cacheCompression: false, // 关闭压缩
},
},
// {
// loader: "ts-loader",
// options: {
// appendTsSuffixTo: [/\.vue$/]
// }
// },
]
},
],
}
}
function CssProcess(type) {
return [
isDevelopment ? 'vue-style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
['postcss-preset-env'],
],
},
},
},
type
].filter(Boolean);
}
babel.config.js
module.exports = {
presets: [
"@vue/cli-plugin-babel/preset",
[
'@babel/preset-env',
{
corejs: 3,
useBuiltIns: 'usage',
modules: false
}
],
[
'@babel/preset-typescript',
]
],
plugins: [
["@babel/plugin-proposal-private-methods", { "loose": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }],
["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
["@babel/plugin-transform-typescript", { "loose": true }]
]
}
eslintrc.js
module.exports = {
root: true,
env: {
node: true
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended"
],
parserOptions: {
parser: "@babel/eslint-parser"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2016",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "Node",
"strict": true,
"jsx": "preserve",
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["ESNext", "DOM"],
"skipLibCheck": true,
"noEmit": false
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue", "src/components/Home/.vue.ts"],
"references": [{ "path": "./tsconfig.node.json" }]
}
tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true
}
}
package.json
{
"name": "src",
"version": "1.0.0",
"description": "",
"main": "./src/index.ts",
"scripts": {
"dev": "cross-env NODE_ENV=\"development\" webpack-dev-server",
"build": "cross-env NODE_ENV=\"production\" npx webpack --config ./webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-syntax-typescript": "^7.20.0",
"@babel/plugin-transform-runtime": "^7.21.0",
"@babel/plugin-transform-typescript": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@types/react": "^18.0.28",
"@types/react-dom": "^18.0.11",
"@types/react-router-dom": "^5.3.3",
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/preload-webpack-plugin": "^2.0.0",
"babel-loader": "^9.1.2",
"babel-preset-react-app": "^10.0.1",
"copy-webpack-plugin": "^11.0.0",
"core-js": "^3.29.0",
"cross-env": "^7.0.3",
"css-loader": "^6.7.3",
"css-minimizer-webpack-plugin": "^4.2.2",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-vue": "^9.9.0",
"eslint-webpack-plugin": "^4.0.0",
"html-loader": "^4.2.0",
"html-webpack-plugin": "^5.5.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.2",
"postcss": "^8.4.21",
"postcss-loader": "^7.0.2",
"postcss-preset-env": "^8.0.1",
"react-refresh": "^0.14.0",
"sass": "^1.58.3",
"sass-loader": "^13.2.0",
"style-loader": "^3.3.1",
"thread-loader": "^3.0.4",
"ts-loader": "^9.4.2",
"typescript": "^4.9.5",
"unplugin-auto-import": "^0.15.1",
"unplugin-vue-components": "^0.24.1",
"url-loader": "^4.1.1",
"vue-loader": "^17.0.1",
"vue-style-loader": "^4.1.3",
"vue-template-compiler": "^2.7.14",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.11.1",
"workbox-webpack-plugin": "^6.5.4"
},
"browserslist": [
"last 6 version",
"> 1%",
"not dead"
],
"dependencies": {
"element-plus": "^2.2.36",
"vue": "^3.2.47",
"vue-router": "^4.1.6"
}
}