# @ysfe/vue-default-config

# Introduction

[![npm version](https://badge.fury.io/js/%40ysfe%2Fvue-default-config.svg)](https://badge.fury.io/js/%40ysfe%2Fvue-default-config)
[![NPM downloads](https://img.shields.io/npm/dm/%40ysfe%2Fvue-default-config.svg?style=flat)](https://npmjs.org/package/ysfe/vue-default-config)

> desc: 宇石前端, vue 项目通用配置
> version: 1.0.0 (vue2.x)

## 简介

这个插件对 vue 项目常用的配置能力进行了封装, 提供了一套约定式的环境变量配置, 以及将一些能力进行了默认集成

## 安装&使用

1.  安装
    1. 配置中心方式: `yarn add @ysfe/vue-default-config@latest --dev`
    2. 正常方式: `yarn add @ysfe/vue-default-config --dev`
2.  使用默认配置

    1. **js 类型**配置项

        vue.config.js

        ```
          const config = require('@ysfe/vue-default-config').default
          module.exports = config
        ```

        babel.config.js

        ```
          module.exports = require('@ysfe/vue-default-config/config/babel.config')
        ```

        .eslintrc.js

        ```
        module.exports = require('@ysfe/vue-default-config/config/.eslintrc')
        ```

        babel.config.js

        ```
         module.exports = require('@ysfe/vue-default-config/config/babel.config')
        ```

        jest.config.js

        ```
        module.exports = require('@ysfe/vue-default-config/config/jest.config')

        ```

        prettier.config.js

        ```
        module.exports = require('@ysfe/vue-default-config/config/prettier.config')

        ```

        commitlint.config.js

        ```
        module.exports = require('@ysfe/vue-default-config/config/commitlint.config')
        ```

    2. **json**类型配置项

        tsconfig.json

        ```
         {
             "extends": "@ysfe/vue-default-config/config/tsconfig.json",
             "compilerOptions": {
                 "baseUrl": "."
             },
             "include": [
                "src/**/*.ts",
                "src/**/*.tsx",
                "src/**/*.vue",
                "__test__/*.ts",
                "__test__/**/*.ts"
             ],
             "exclude": ["node_modules"]
         }
        ```

        jsconfig.json

        ```
        {
             "extends": "@ysfe/vue-default-config/config/jsconfig.json",
             "compilerOptions": {
                 "baseUrl": "."
             },
             "include": [
                "src/**/*.js",
                "src/*.js",
                "src/**/*.vue",
                "__test__/*.js",
                "__test__/**/*.js"
             ],
             "exclude": ["node_modules"]
         }
        ```

3.  自定义覆盖 (根据项目特性定制)

    > 这个能力可以不用, 但必须得有!!!

    以 `vue.config.js` 举例

        ```
        const config = require('@ysfe/vue-default-config').default

        // 通过对原始导出配置对象中变量覆盖达到更改自定义配置目的
        config.assetsDir = '/'

        module.exports = config

        ```

    js 类型配置则需遵循官方定义的变量覆盖方式, 一般为正常配置即可, 如:

    ```
    {****
        "extends": "@ysfe/vue-default-config/config/tsconfig.json",
        "compilerOptions": {
            "baseUrl": ".",
            "allowJs": true // 类似这种, 正常配置即可.
        }
    }
    ```

<br />
<br />
<br />

## 支持

> 相对于 vue 官方的脚手架, 在这里我们增加了一些独有能力, 和默认插件、配置集成

---

### 配置中心

> 解决前端项目碎片化, 提供统一的配置维护方式

#### 前言

参考后端的配置中心, 在前端项目日益琐碎的日子里, 配置中心对于一些能力还是挺香的, 比如: 统一管理的插件, 基础库版本等.

这些能力本身对于不同项目来讲差异不大, 但是每个项目维护一份的话, 日积月累下来, 进行优化改动也是一个不小的工作.

so, 就有了当前这个组件, 通过类似配置中心的方式, 对一些共性内容进行统一维护.

#### 原理

如果熟悉 npm 包管理特性的话, 那么不难发现, npm 的依赖版本分为如下几种类型: `1.1.1`、`^1.1.1`、`next`、`latest`.

前面两种暂且不提, 就后面两种来讲, 每次我们执行 yarn 时, npm 包管理器会去请求 `npm repo` 获取最新的 `next` and `latest`.

了解了这个知识点, 那么我们就不难实现配置中心的能力. 即: **每次配置中心变更后, 其他子项目在运行时, 可以通过 latest 主动拉取最新的依赖**. 剩下的, 只需要将依赖作为配置中心, 以及在项目中, 将插件配置继承依赖中的通用配置即可.

---

### 环境变量

> 约定式设计, 一般不新增

```
// 文本项: app 运行时相对路径 (部署应用包时的基本 URL)
VUE_APP_PUBLIC_PATH=/
// 文本项: app 静态资源路径
VUE_SUBDIRECTORY_PATH=
// 开关项: 是否启用 sentry 插件
VUE_ENABLE_SENTRY=0
// 开关项: 是否启用保存时, lint 校验
VUE_DEV_LINT_ON_SAVE=1
// 文本项: 本地调试端口
VUE_DEV_SERVER_PORT=9000
// 开关项: 是否自动打开 chrome 浏览器 (mac环境) 0:关闭, 1: 开启(默认), 2: 开启跨域访问
VUE_DEV_OPEN_CHROME=0
```

---

### 动态代理

> 解决前端接口调试中的跨域问题
> code source: [传送门](/src/dev-server/index.ts)

#### 前言

webpack4 集成的 webpack-dev-server 中提供的有接口代理能力, 但这个能力是静态的. 本质上是在 dev server 服务启动时, 向 express 服务器中注入了一个 `http-proxy-middleware` 代理服务.

而我们实际使用的时候, 因为 devserver 提供的这个代理是一个静态代理, 在我们切换环境调试的时候不可避免的需要重启服务. 为了解决这个问题, 最方便的手段就是动态代理.

#### 实现方式

**服务注入**: devserver 配置参数中, 提供的有一个 `after(app, server, compiler):void` 事件, 通过这个事件, 我们可以拿到 express 服务器对象. 然后, 将我们自己的代理注册进去。

**动态代理**: 关于动态代理的实现, 我用的是通过`headers`运输信息, 将请求的目标地址, 和解决跨域所需的`Origin`,`Host` 参数通过 headers 携带过来.

**解析**: 请求来源 和 服务地址 分别通过`Form` 、`Target` (不区分大小写) 获取. 然后对这两个地址进行 fix, 保证地址的完整性, 改动: `//server` -> `http://server`, `server` -> `http://server`, 同时, from 地址也根据 target 做了 https 判断。

**接口代理**: 这里采用的是在拦截到请求时, 创建代理实例并请求的方式, 类似于拦截器内手工引用一个拦截器这个样子. 感兴趣可以看下源码.

#### 使用方式

1. 通过代理接口发送请求

    ```
    // origin
    Axios({
       baseUrl: 'http://server', // 服务地址
       url: '/api'
    })
    // use proxy
    Axios({
       baseUrl: '/proxy', // 服务地址
       url: '/api'
       headers: {
          From: 'http://front', // changeOrigin 地址
          Target: 'http://server' // 服务地址
       }
    })
    ```

2. 注意事项: 如果 server 校验 https, 那么请保证 前后端项目均使用 https

---

### webpack 配置

#### 前言

`vue.config.js` 中, 允许通过 `configureWebpack` 和 `chainWebpack` 两种方式来添加 webpack 配置, 综合考虑后, 我们只用 `chainWebpack` 来添加 webpack 配置, 主要因为这样方式与`@vue/cli-service`结合的更好.

#### 插件集成情况

> 仅列举非 vue2 内置插件

| 插件                         | 说明                                                   |
| ---------------------------- | ------------------------------------------------------ |
| speed-measure-webpack-plugin | smp 编译性能分析, 由于框架限制, 仅支持 loader 性能分析 |
| webpack-bundle-analyzer      | 依赖占比分析                                           |
| IgnorePlugin                 | 通过 ignore 插件, 删除 moment 语言包                   |
| less-clean-css-plugin        | less 清理多余样式插件, 实际是通过 vue css 属性添加上的 |
| svg-spile-loader             | 为 <svg-icon> 组件提供支持                             |
|                              |                                                        |

#### 自定义插件接入

```
// 在 vue.config.js 中


const config = require('@ysfe/vue-default-config').default

// webpack-chain附加
config.chainWebpack = (chain)=> {
    // 先执行原始配置
    config.chainWebpack(chain)
    // 添加自定义配置
    // ...
}

// configureWebpack 附加 (不推荐)
config.configureWebpack = {
   // ...
}

module.exports = config
```

---

### 编译性能分析

#### 前言

目前框架的性能分析能力通过 `speed-measure-webpack-plugin` (loader 打包耗时分析) 和 `webpack-bundle-analyzer`(资源占比分析) 两部分组成.

执行编译命令后, 结果会输出三份:

1. smp
    1. 输出到控制台展示简要信息
    2. 输出到 `./logs/smp.md`
2. analyzer - 打开一个 web 服务.
    1. 地址一般为(会自动打开): `http://127.0.0.1:8888/`

#### 使用

> 建议在 package.json 中, 增加性能分析命令, 格式如下:

```
{
  "analyzer": "vue-cli-service build --analyzer --disable-sentry"
}
```

---

### UI 组件库按需加载自动引入

#### 原理

通过对`package.json`的扫描, 根据关键字获取三个库是否被添加, 如果添加了, 就在 `babel.config.js` 中, 导入按需加载插件.

#### 支持

-   ant-design-vue
-   vant
-   element-ui

## 前置

需要继承 `babel.config.js` 配置

---

### 关于 nodeJs polyfill 在 webpack5 中被移除的说明

https://webpack.docschina.org/configuration/resolve/#resolvealias

### 默认提供 @/\* 及 @views 支持

```
config.resolve.alias
        .set('@/*', resolve('src/'))
        .set('@assets', resolve('src/assets'))
        .set('@components', resolve('src/components'))
        .set('@plugins', resolve('src/plugins'))
        .set('@views', resolve('src/views'))
        .set('@router', resolve('src/router'))
        .set('@store', resolve('src/store'))
        .set('@utils', resolve('src/utils'))
        .end()
```

---

### 全局样式变量注入

一般我们常用 less, scss 写样式, 然后有些会用到全局变量的地址, 我看了之前的一些项目基本上都是通过 `globalStyle` 写入全局样式变量. 但这样, 会导致编译代码与业务代码耦合, 为了解耦, 我们将全局样式的加载方式从原有的 `globalStyle` 修改为 通过
`./src/assets/(less|scss)/variable.(less|scss)` 导入全局样式变量

**注意**: 如非必要, 尽量不要向`variable.(less|scss)` 中写入全局样式(正常样式, 不做 referer 使用那种). 这样会导致打包的样式内, 每个文件都包含了这个样式, 对性能有一定影响.

---

### 关闭 prefetch, preload

经过上次教训, 虽然这两个功能对性能优化有帮助, 但是在我们无法针对单一项目做极致优化的场景下, 全量的 prefetch 会带来大量的无效流量. 故在此默认关闭

---

### 动态 ts/js 项目检查

为了后续向 ts 迁移, 我们通过 `globs` 扫描 `./src/main.(tj)s` 来判断当前是哪种类型项目, 然后改写 `entry` 入口.

## 基础库

> 仅列举几项重要的

-   **vue** 2.6.11
-   **webpack** 4.46.0
-   **webpack-chain** 6.5.1 | wepack 配置链式操作
-   **minimist** 2.6.11 | 命令行参数解析

## 项目说明

-   [通用开发指引](docs/dev.md)
-   [目录设计](docs/目录结构.md)
-   [可选插件资料](docs/插件集成.md)

## 迭代约定

1. 环境变量
    1. 环境变量仅允许**新增**, 一般不允许**修改**或**删除**
    2. 环境变量命名应遵循**vue**官方命名格式. 只有 NODE*ENV, BASE_URL 和以 \*\*VUE_APP*\*\* 开头的变量将通过 webpack.DefinePlugin 静态地嵌入到客户端侧的代码中.

## RoadMap

1. webpack 插件
    - postcss 系列, css 资源优化.

## 发行版本

### v1.4.x

> notes:
>
> 1. 调整 http-proxy-middleware 配置. 关闭 `xfwd` 开关. 目测, 没啥影响

### v1.3.1

> notes:
>
> 1. 增加版本锁定操作 (webpack-dev-server 大更新, 没预料到)
> 2. 更新 webpack-dev-server 配置

### v1.2.15

> notes:
>
> 1. 更新 `prettier.config.js`, 解决 html 格式化换行样式问题

### v1.2.14

> notes:
>
> 1. 更新 `prettier.config.js`, 注释 过时属性 `jsxBracketSameLine`

### v1.2.11

> notes:
>
> 1. 新增 `process.env.command` 变量, 值: `serve`, `build`, `build:staging` .
>
> -   主要应用场景: 用来区分本地, 部署环境. 判断依据: `process.env.command === > 'serve'`

### v1.2.5

> notes:
>
> 1. 撤回 jest 版本至 26.6.3

### v1.2.1

> notes:
>
> 1. 更新 eslint 规则, 集成宇石前端通用 eslint 规范

### v1.1.21

> notes:
>
> 1. 优化动态代理支持

### v1.1.21

> notes:
>
> 1. 更改 stylelint 配置扫描错误

### v1.1.20

> notes:
>
> 1. 升级 sentry, 补充忽略规则

### v1.1.19

> notes:
>
> 1. 升级 sentry, 更改采样比例

### v1.1.17

> notes:
>
> 1. 修复一些已知 bug.

### v1.1.5

> notes:
>
> -   更新 sentry-webpack-plugin

### v1.0.1 版本

> notes:
>
> -   修复一些已知问题
> -   集成一些 postcss 插件, 优化样式输出
> -   性能优化: 启用 spriteChunk 模块

### v1.0.0 版本

> notes:
>
> -   首次发布
