# MultiOriginWebpackPlugin

## 提示
1. 此插件依赖于`html-webpack-plugin`插件
2. 该插件会强制更改项目中的publicPath配置
3. webpack 3/4 构建时，css样式中使用了相对路径的url，如`../img/xxx.png`，若构建后引用的资源路径不正确，需要将使用了「ExtractTextPlugin」或「MiniCssExtractPlugin」**loader**的publicPath重设为`'../'`，可参考该文档[MiniCssExtractPlugin](https://webpack.js.org/plugins/mini-css-extract-plugin/#the-publicpath-option-as-function)。webpack 5 下插件会在构建产物阶段自动重写 CSS 内的资产路径，无需该手动配置

## 兼容性

| Webpack  | html-webpack-plugin | 支持 |
|----------|---------------------|------|
| 3.x      | 3.x                 | ✓    |
| 4.x      | 3.x / 4.x           | ✓    |
| 5.x      | 4.x / 5.x           | ✓    |

## 下载

```bash
npm i @xysfe/multi-origin-webpack-plugin
```

## 使用方式
**webpack.config.js**

```js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { web: MultiOriginWebpackPlugin } = require('@xysfe/multi-origin-webpack-plugin')

module.exports = {
  entry: 'index.js',
  output: {
    path: __dirname + '/dist',
    filename: 'index_bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new MultiOriginWebpackPlugin()
  ]
}
```

**vue.config.js**

```js
const { web: MultiOriginWebpackPlugin } = require('@xysfe/multi-origin-webpack-plugin')

module.exports = {
  chainWebpack: config => {
    config
      .plugin('multi-origin')
      .use(MultiOriginWebpackPlugin)
  }
}
```

**SSR 项目**

```js
const { ssr: MultiOriginWebpackPlugin } = require('@xysfe/multi-origin-webpack-plugin')
// 用法同上
```

### **注意事项**
插件强依赖于**NODE_ENV**环境变量，用于处理线上发布后会导致测试环境资源不可访问的现状，若没有该变量则会退出构建。

**正式环境的NODE_ENV必须是production，否则无法构建出正确的资源路径。**

NODE_ENV环境变量注入方式:
```json5
// file: package.json
// webpack
{
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack...",
    "dist": "cross-env NODE_ENV=production webpack..."
  }
}

```
```json5
// vuecli
// vuecli默认的mode为production
{
  "scripts": {
    "dev": "vue-cli-service build --mode development",
    "dist": "vue-cli-service build"
  }
}
```
## 功能
1. 插件将会注入全局变量，来获取到PHP返回的CDN地址，并且拼接成一个带协议和域名的链接，生成的页面片如下

```html
<!DOCTYPE html>
<html>
  <head>
    <script>var __global_cdn__=(function(b,a){if(a.indexOf('http')===0){return a}else{if(a.indexOf('//')===0){return b.protocol+a}else{return b.protocol+'//'+b.host+a}}})(location, '{$CDN}')</script>
    <meta charset="utf-8">
    <title>Webpack App</title>
  </head>
</html>
```

2. 插件会检测代码中是否有指定的代码片段，在编译过程中提出警告，效果如下

![示例图片](./example.jpg)

3. 插件会在js中注入动态 public path，用于实现多域名cdn分离的效果，注入后的代码如下

```js
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "/static/insuranceV2/";
/******/
/******/ 	// set dynamic webpack public path by multi-origin-webpack-plugin
/******/ 	__webpack_require__.p = window.__global_cdn__ ? window.__global_cdn__ + '/insuranceV2/' : '/static/insuranceV2/';
/******/
```

## 配置项

|  Name  | Type  |  Default  | Description  |
|  ----  | ----  |  ----  | ----  |
| regex  | {Array} | ['xiaoyusan.com']  | 检测代码中需要匹配的字符串 |
| shouldCheck  | {Boolean} | true  | 选择是否需要提示域名警告 |
| fixedPublicPath  | {Boolean} | false  | 选择是否保持原来的publicPath配置（ssr开发环境使用，仅 SSR 模式） |
| monitorInclude  | {Boolean\|String} | true  | 注入到 `<head>` 的 monitor include 标签。`true` 使用默认路径，字符串指定自定义路径，`false` 关闭注入 |
| patchAssetRules  | {Boolean} | true  | webpack 5 下自动重写 CSS 产物中的资产路径为 CSS 相对路径（跟随 CSS 所在域名），避免 `{$CDN}` 占位符/publicPath 残留在静态 CSS 中导致 404，设为 `false` 关闭 |

### patchAssetRules 说明

webpack 5 的 asset modules（图片/字体等）在 CSS 链路中会把 publicPath（web 模式已被本插件改写为 `{$CDN}` 占位符，ssr 模式为原始 `/static/xxx/` 路径）硬拼进产物。CSS 是纯静态文件，不经过发布系统的占位符替换，残留内容会被浏览器按相对路径解析出 404。

处理策略（不修改任何 module rule）：

- **JS 链路不干预**：asset modules 默认导出为运行时表达式（`__webpack_require__.p + 文件名`），由插件注入的 RuntimeModule 在运行时动态赋值、跟随 `__global_cdn__`，天然正确
- **CSS 链路在 processAssets 阶段重写**：把 CSS 内的 `<垃圾前缀>{$CDN}/<path>/`（含 percent-encode 变体）与 ssr 场景的 `../<原始publicPath>` 统一替换为「CSS 文件到产物根的相对路径」（如 `css/main.css` 内得到 `../img/xxx.png`），资源始终跟随 CSS 所在域名

已知限制：

- CSS sourcemap（`.css.map`）中的 `sourcesContent` 不参与重写，map 内可能残留占位符（仅影响 sourcemap 展示，不影响资源加载）
- 若业务 CSS 中手写了字面量 `{$CDN}`（非资产引用），也会被一并替换
