npm package: @gzxijiu/acceptance
Description: Guizhou Xijiu Frontend Code Acceptance Engine.
Author: liufaxiang
Latest version: 0.4.0

<h1 align="center">
  <a href="https://npmjs.com/package/@gzxijiu/acceptance" target="_blank" rel="noopener noreferrer">
    @gzxijiu/acceptance <sup><img alt="version" src="https://img.shields.io/npm/v/@gzxijiu/acceptance.svg?style=flat-square&color=white&label="></sup>
  </a>
</h1>

<p align="center">
  贵州习酒前端代码验收引擎
</p>

<p align="center">
  <a href="https://github.com/antfu/eslint-config"><img alt="code style" src="https://antfu.me/badge-code-style.svg"></a>
  <a href="https://conventionalcommits.org"><img alt="conventional commits" src="https://img.shields.io/badge/commits-Conventional-FE5196.svg?logo=conventionalcommits"></a>
  <a href="https://semantic-release.gitbook.io"><img alt="semantic release" src="https://img.shields.io/badge/release-semantic-e10079?logo=semantic-release"></a>
</p>

<br>

## 特性

- 提升验收的效率、准确性和一致性
- 支持一键验收
- 支持演练模式
- 融入开发环节，降低验收成本，杜绝额外回归
- 多框架支持
- 多包管理器支持，自动检测包管理器
- 基于 AST 的调试工具自动集成
- 基于 AST 的源码映射自动配置（基础）
- 支持可视化展示 ESLint 配置
- 支持检测 ESLint 忽略
- 支持检测高风险许可证
- 支持检测未标记为废弃但停止维护的知名依赖

<br>

## 一键验收

```shell
npx -y @gzxijiu/acceptance@latest
```

<br>

## 演练模式

演练模式下不会产生文件变更，适用于需要微调配置、整改后复核的情况

<br>

## 验收条目

<table>
  <tr>
    <th colspan="2" align="center">验收条目</th><th align="center">验收方式</th>
  </tr>
  <tr>
    <td colspan="2" align="center">代码完整性</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">文档完整性</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">统一技术栈</td><td align="center">人工</td>
  </tr>
  <tr>
    <td rowspan="2" align="center" valign="center">代码安全性</td><td align="center"><a href="#XSS">XSS</a></td><td align="center">不完全自动化</td>
  </tr>
  <tr>
    <td align="center">其它</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">依赖安全性</td><td align="center">自动化</td>
  </tr>
  <tr>
    <td rowspan="2" align="center" valign="center">版权安全性</td><td align="center">依赖版权</td><td align="center">自动化</td>
  </tr>
  <tr>
    <td align="center">素材版权</td><td align="center">人工</td>
  </tr>
  <tr>
    <td rowspan="4" align="center" valign="center">缺陷可控性</td><td align="center">源码映射</td><td align="center"><a href="#源码映射">不完全自动化</a></td>
  </tr>
  <tr>
    <td align="center">调试成本</td><td align="center">不完全自动化</td>
  </tr>
  <tr>
    <td align="center">自动化测试</td><td align="center">人工</td>
  </tr>
  <tr>
    <td align="center">监控告警</td><td align="center">人工</td>
  </tr>
  <tr>
    <td rowspan="2" align="center" valign="center">设备兼容性</td><td align="center">语法转译</td><td align="center"><a href="#设备兼容性">不完全自动化</a></td>
  </tr>
  <tr>
    <td align="center">polyfill</td><td align="center"><a href="#设备兼容性">人工</a></td>
  </tr>
  <tr>
    <td colspan="2" align="center">系统性能</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">用户体验</td><td align="center">人工</td>
  </tr>
  <tr>
    <td rowspan="6" align="center" valign="center">代码规范</td><td align="center">格式化校验</td><td rowspan="6" align="center">自动化</td>
  </tr>
  <tr>
    <td align="center">财务计算</td><
  </tr>
  <tr>
    <td align="center">包管理器与镜像</td>
  </tr>
  <tr>
    <td align="center">Git 钩子</td>
  </tr>
  <tr>
    <td align="center">.gitignore</td>
  </tr>
  <tr>
    <td align="center">约定式提交</td>
  </tr>
  <tr>
    <td rowspan="2" align="center" valign="center">发版规范</td><td align="center">发版流程</td><td align="center">人工</td>
  </tr>
  <tr>
    <td align="center">缓存策略</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">操作手册</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">保密义务</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">售后保障</td><td align="center">人工</td>
  </tr>
  <tr>
    <td colspan="2" align="center">未尽事宜</td><td align="center">人工</td>
  </tr>
</table>

<br>

## 多框架支持

- Vue 3
- Nuxt
- Vanilla JavaScript
- Vue 2/3 isomorphic
- React
- Next
- Vue 2
- ...

<br>

## 多包管理器支持

- [only-allow](https://github.com/pnpm/only-allow)
- [ni](https://github.com/antfu-collective/ni)

<br>

## XSS

|             描述             |           语法            |                             解决方案参考                             |
| :--------------------------: | :-----------------------: | :------------------------------------------------------------------: |
|        Vue 操作 HTML         |         `v-html`          | [vue-dompurify-html](https://github.com/LeSuisse/vue-dompurify-html) |
|       React 操作 HTML        | `dangerouslySetInnerHTML` |           [DOMPurify](https://github.com/cure53/DOMPurify)           |
| Vanilla JavaScript 操作 HTML |        `innerHTML`        |                            `textContent`                             |
|         动态执行代码         |          `eval`           |                             非必要不使用                             |
|         动态创建函数         |        `Function`         |                             非必要不使用                             |
|             ...              |                           |                                                                      |

<br>

## 源码映射

### Vite

```ts
// vite.config.*
import { defineConfig } from 'vite'

export default defineConfig(({ command, mode }) => {
  return {
    build: {
      sourcemap: true,
      rollupOptions: {
        output: {
          sourcemapExcludeSources: mode === 'prod',
        },
      },
    }
  }
})
```

### Nuxt

```ts
// nuxt.config.*
import process from 'node:process'

export default defineNuxtConfig({
  sourcemap: {
    server: true,
    client: true,
  },
  vite: {
    build: {
      sourcemap: true,
      rollupOptions: {
        output: {
          sourcemapExcludeSources: process.env.VITE_MODE === 'prod',
        },
      },
    },
  },
})
```

### Next

```ts
// next.config.*
import process from 'node:process'

const nextConfig = {
  productionBrowserSourceMaps: true,
  webpack(config) {
    config.devtool = process.env.NODE_ENV === 'prod' ? 'nosources-source-map' : 'eval-source-map'
    return config
  },
}

export default nextConfig
```

### webpack

```ts
// webpack.config.*
import process from 'node:process'

module.exports = {
  devtool: process.env.NODE_ENV === 'prod' ? 'nosources-source-map' : 'eval-source-map',
}
```

> [!CAUTION]
>
> 建议勿将 `.map` 文件部署至公网

<br>

## 设备兼容性

由于 Vite、webpack 和 Babel 配置方式丰富多样，目前仅支持手动配置兼容性，下方提供参考示例：

### Vite

```shell
npm i @vitejs/plugin-legacy browserslist browserslist-to-esbuild -D
```

```ts
// vite.config.ts
import legacy from '@vitejs/plugin-legacy'
import browserslistToEsbuild from 'browserslist-to-esbuild'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    target: browserslistToEsbuild()
  },
  plugins: [
    legacy(),
  ],
})
```

https://github.com/vitejs/vite/issues/11489

### webpack / Vue CLI

#### Vue

```shell
npm i @vue/cli-plugin-babel babel-loader -D
```

```json5
// package.json
{
  "babel": {
    "presets": [
      "@vue/cli-plugin-babel/preset"
    ]
  }
}
```

#### Vanilla JavaScript

```shell
npm i @babel/core @babel/preset-env babel-loader -D
```

```json5
// package.json
{
  "babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "corejs": 3,
          "useBuiltIns": "usage"
        }
      ]
    ]
  }
}
```

#### React

```shell
npm i @babel/core @babel/preset-env @babel/preset-react babel-loader -D
```

```json5
// package.json
{
  "babel": {
    "presets": [
      [
        "@babel/preset-env",
        {
          "corejs": 3,
          "useBuiltIns": "usage"
        }
      ],
      "@babel/preset-react"
    ]
  }
}
```

#### 验证方法

复制（包括但不限于）下方代码到项目中，打包后在产物中搜索 `?.`/`??`/`??=` 等新语法是否被正确转译，`replaceAll` 等新 API 是否被正确 polyfill：

```ts
// TODO: 示例代码，用于验证兼容性配置是否生效，验证后务必删除
let result = null
const user = {}
result ??= user?.name?.replaceAll(' ', '_') ?? '@gzxijiu/acceptance'
```

<br>