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