---
# System prepended metadata

title: Vue3+TS+多版型 webpack打包
tags: [Vue-cli, Vue3]

---

# 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]"
          }
        }
      });
  }
```