const path = require("path"); const resolve = dir => path.join(__dirname, dir); const BundleAnalyzerPlugin = require("webpack-bundle-analyzer"); const TerserPlugin = require("terser-webpack-plugin"); const CompressionWebpackPlugin = require("compression-webpack-plugin"); const productionGzipExtensions = ["js", "css"]; const px2rem = require("postcss-px2rem"); const SkeletonWebpackPlugin = require("vue-skeleton-webpack-plugin"); const _env = process.env; // 不支持解构 // == ant-design 主题覆盖 less (条件编译) == // let antDesignVariables = {}; /* IFTRUE_ANT_DESIGN */ antDesignVariables = { modifyVars: { hack: `true; @import "~@/styles/loader/ant-design.variables";` }, javascriptEnabled: true }; /* FITRUE_ANT_DESIGN */ // es5语法, 导出一份拷贝: 修改需要重新运行 module.exports = { // 基础配置 publicPath: "./", outputDir: _env.DIR_OUT_PUT || "dist", assetsDir: "", lintOnSave: _env.NODE_ENV === "development", runtimeCompiler: true, productionSourceMap: false, // 本地代理 devServer: { port: _env.VUE_APP_DEV_PORT, proxy: { [_env.VUE_APP_DEV_PROXY]: { // target字段为空编译报错 target: _env.VUE_APP_BASE_API, changeOrigin: true, pathRewrite: { ["^" + _env.VUE_APP_DEV_PROXY]: "" } } }, disableHostCheck: true }, // css配置: 自动加载 loaderOptions 对 stylus 和 less 都无效 css: { extract: true, sourceMap: false, loaderOptions: { // 自动加载仅导入主题: less sass stylus 方式不相同 - 细节详见 README.md stylus: { import: "~@/styles/loader/variables" }, postcss: { plugins: [ //基准大小 baseSize,需要和flexRem.js中相同 px2rem({ remUnit: _env.VUE_APP_REM_UNIT }) ] }, less: antDesignVariables } }, chainWebpack: config => { // 运行 Webpack Bundle Analyzer插件:npm run analyze if (_env.IS_ANALYZE) { config .plugin("webpack-report") .use(BundleAnalyzerPlugin.BundleAnalyzerPlugin, [ { analyzerMode: "static" } ]); } // 添加别名 config.resolve.alias .set("@", resolve("src")) .set("storage", resolve("src/utils/storage")) .set("extend", resolve("src/styles/extend")) .set("mixin", resolve("src/styles/mixin")) .set("dinkle", resolve("src/modules/dinkle")) // 町洋阿拉丁 .set("opay", resolve("src/modules/opay")); // 欧非项目 // 模块配置使用链式语法 config.module // 配置pug/jade .rule("pug") .test(/\.pug$/) .use("pug-plain-loader") .loader("pug-plain-loader") .end(); }, configureWebpack: config => { // 自动识别文件后缀 config.resolve.extensions = [ ".js", ".vue", ".json", ".css", ".styl", ".sass", ".scss", ".less" ]; // vue骨架屏插件配置 if (_env.VUE_APP_SKELETON) { config.plugins.push( new SkeletonWebpackPlugin({ webpackConfig: { entry: { app: resolve("src/config/skeleton/conf") } }, minimize: true, quiet: true }) ); } // 配置条件编译: js-conditional-compile-loader 下 npm 和 cnpm 不能混用 config.module.rules.push({ test: /\.js$/, include: [resolve("src"), resolve("test")], use: [ { loader: "js-conditional-compile-loader", options: { isDebug: _env.NODE_ENV == "development", // optional, this is default // 自定义 flag (.env 是 string 化的值, 非合法 json: string 可使用 includes 函数, 单独效验使用正则) ANT_DESIGN: _env.VUE_APP_PLATFORM.includes( _env.VUE_APP_UI_ANT_DESIGN ), QUASAR: _env.VUE_APP_PLATFORM.includes(_env.VUE_APP_UI_QUASAR), ELEMENT: _env.VUE_APP_PLATFORM.includes(_env.VUE_APP_UI_ELEMENT) } } ] }); // 开发环境独立配置 devtool if (_env.NODE_ENV === "development") { config.devtool = "source-map"; } // 生产环境立配置 if (_env.NODE_ENV === "production") { // 开启gzip压缩 if (_env.IS_GZIP) { config.plugins.push( new CompressionWebpackPlugin({ filename: "[path].gz[query]", algorithm: "gzip", test: new RegExp( "\\.(" + productionGzipExtensions.join("|") + ")$" ), threshold: 10240, minRatio: 0.8 }) ); } // webpack4语法返回一个将会被合并的对象 return { output: { // 输出重构: 打包编译后的文件名称【模块名称.chunkhash.版本号】- 添加文件夹(./js/) filename: `./js/[name].[chunkhash].${_env.VUE_APP_VERSION}.js`, chunkFilename: `./js/[name].[chunkhash].${_env.VUE_APP_VERSION}.js` }, // 到打包chunk警告配置 performance: { hints: "warning", // 入口起点的最大体积 整数类型(以字节为单位) maxEntrypointSize: 50000000, // 生成文件的最大体积 整数类型(以字节为单位 300k) maxAssetSize: 30000000, // 只给出 js 文件的性能提示 assetFilter: function (assetFilename) { return assetFilename.endsWith(".js"); } }, // 拆包: 大文件拆分提升加载速度和懒加载 optimization: { runtimeChunk: "single", splitChunks: { chunks: "all", maxInitialRequests: Infinity, minSize: 20000, // 依赖包超过20000bit将被单独打包 cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name (module) { const packageName = module.context.match( /[\\/]node_modules[\\/](.*?)([\\/]|$)/ )[1]; return `npm.${packageName.replace("@", "")}`; } } } }, // 代码压缩去除打印: npm i uglifyjs-webpack-plugin@1 需要使用低版本, 新版本不识别 const 关键字 - 报 npm audit fix minimizer: [ new TerserPlugin({ cache: false, sourceMap: false, parallel: true, // 使用多进程并行运行来提高构建速度。默认并发运行数:os.cpus().length - 1。 terserOptions: { compress: { drop_debugger: true, // 去除 debugger drop_console: true, // 生产环境自动删除 console dead_code: true // 去除不可达代码: 如 if (false) { ... } }, warnings: false } }) ] } }; } }, // quasar: vue add quasar 自动添加 pluginOptions: { quasar: { importStrategy: "manual", rtlSupport: false } }, transpileDependencies: ["quasar"] };