# Vue3+TS+多版型 webpack打包 ###### tags: `Vue-cli`、`Vue3` ### 使用到的套件 webpack、compression-webpack-plugin、fs(accessSync, constants) fs主要用來測試該檔案物件存不存在,給多版型使用 ### webpack > devServer ```javascript= devServer: { host: "localhost", port: 8080, open: false, hot: true, overlay: { warnings: false, errors: true }, proxy: { "/api": { target: proxyUrl.apiUrl, ws: false, changOrigin: true, pathRewrite: { "^/api": "" } } } } ``` 此為本地server設定,proxy用來將本地domain路徑轉址為api路徑,pathRewrite會將程式內所有有寫到api的地方都替換成設定的路徑 ### CSS(SCSS) ```javascript= css: { sourceMap: debug, loaderOptions: { // 將 option 傳遞給 sass loader sass: { // 允許在所有被處理的文件之間共享變量 prependData: `$ResourceCdnUrl:"${resourceCDN}";` } } }, ``` 這邊為scss在執行時的全域參數設定方式,通常用來設定CDN網址 ### configureWebpack #### resolve 此為webpack解析的方式,包含路徑別名、檔案位置、副檔名,都可以在這設定,讓webpack在打包的時候可以按照這些設定來進行打包,亦可剔除某些不想打包近的東西。 ```javascript= resolve: { // 創建別名讓 import module 時更加簡單 alias: { "@": path.resolve(__dirname, "src"), "@M": path.resolve(__dirname, "mock"), vue$: "vue/dist/vue.runtime.esm-bundler.js", "bn.js": path.resolve(process.cwd(), "node_modules", "bn.js") }, // 告訴 webpack 要去哪個目錄底下找 module modules: [path.resolve(__dirname, `src`), path.resolve(__dirname), path.resolve(__dirname, "node_modules")], // import 時不需要指明副檔名,webpack 會嘗試依陣列內順序去做解析 extensions: [".vue", ".js", ".scss"] } ``` 此外在 vue$ 的地方與 vue2 有些許不同,vue2 使用 vue/dist/vue.runtime.esm.js,vue3 使用 vue/dist/vue.runtime.esm-bundler.js #### plugins 使用 webpack 額外的插件,在編譯時可配置全局變量、直接全域import、壓縮方式與文件讀取方式。 ```javascript= plugins: [ // new BundleAnalyzerPlugin(), // Use modules without having to use import/require new webpack.ProvidePlugin({ $: "jquery", jquery: "jquery", jQuery: "jquery", "window.jQuery": "jquery" }), // Allow global constants configured at compile time new webpack.DefinePlugin({ // SITE_KEY: `"${siteKey}"`, VUE_APP_CDN_URL: `"${resourceCDN}"` }), // Prepare compressed versions of assets to serve them with Content-Encoding new compressionWebpackPlugin({ algorithm: "gzip", test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"), // Only assets bigger than this size are processed. In bytes. threshold: 10 * 1024, // Only assets that compress better than this ratio are processed minRatio: 0.8, deleteOriginalAssets: false }), // 抓出所有 import 路徑在 @/views 內的 vue,比對指定站代號的資料夾內相對應位置有沒有檔案,有就使用指定站代號的 new webpack.NormalModuleReplacementPlugin(/@\/views\/(.*)\.vue$/, (resource) => { const path = resource.request.slice(); const pathWithoutPrefix = path.slice(path.indexOf("@") + 1); const customPath = `/sites/component/${siteCode}${pathWithoutPrefix}`; const isImportFromSites = new RegExp(siteCode).test(resource.context); if (isImportFromSites) { resource.request = path; return; } try { accessSync(`src${customPath}`, constants.F_OK); resource.request = `@${customPath}`; } catch (err) { resource.request = path; } }) ] ``` #### chainWebpack 加上需使用到的loader ```javascript= chainWebpack: (config) => { config.module .rule("ts") .use("ts-loader") .loader("ts-loader") .tap((options) => { // modify the options... return options; }); config.module .rule("pug") .test(/\.pug$/) .oneOf("pug-vue") .use("pug-plain-loader") .loader("pug-plain-loader") .options({ basedir: path.resolve(__dirname, `src`) }) .end(); config.module .rule("pug") .test(/\.pug$/) .oneOf("pug-template") .use("pug-plain-loader") .loader("pug-plain-loader") .options({ basedir: path.resolve(__dirname, `src`) }) .end(); config.optimization.splitChunks({ cacheGroups: { commons: { chunks: "all", name: "common", minChunks: 2, priority: 1 }, libs: { name: "chunk-libs", test: /[\\/]node_modules[\\/]/, chunks: "initial", reuseExistingChunk: true, priority: 0 } } }); config.plugins.delete("preload-index"); config.plugins.delete("prefetch-index"); let rule = config.module.rule("images"); rule.uses.clear(); rule .use("url-loader") .loader("url-loader") .options({ limit: 4096, fallback: { loader: "file-loader", options: { name: "static/img/[name].[hash:8].[ext]" } } }); } ```