# reskript

> Finely maintained scripts for react libs and apps

Latest version **0.26.7** (published 2020-08-09) · MIT license · 0 weekly downloads

## Install

```sh
npm install reskript
pnpm add reskript
yarn add reskript
bun add reskript
```

Provides the command `skr`.

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.26.7 |
| Published | 2020-08-09 |
| First published | 2019-03-03 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 133 |
| Unpacked size | 307.1 KB |
| Known vulnerabilities | 0 (+11 in 3 direct dependencies) |
| Install scripts | no |
| Author | zhanglili |
| Maintainers | buzheng, conwnet, huoyuxuan, otakustay |

## Links

- npm: https://www.npmjs.com/package/reskript
- npm.io page: https://npm.io/package/reskript

## Dependencies (133)

- [ora](https://npm.io/package/ora.md) ^4.0.4
- [glob](https://npm.io/package/glob.md) ^7.1.6
- [less](https://npm.io/package/less.md) 3.9.x
- [svgo](https://npm.io/package/svgo.md) ^1.3.2
- [chalk](https://npm.io/package/chalk.md) ^4.0.0
- [hasha](https://npm.io/package/hasha.md) ^5.2.0
- [yargs](https://npm.io/package/yargs.md) ^15.3.1
- [eslint](https://npm.io/package/eslint.md) ^6.8.0
- [globby](https://npm.io/package/globby.md) ^11.0.0
- [lodash](https://npm.io/package/lodash.md) ^4.17.15
- [rollup](https://npm.io/package/rollup.md) ^1.31.1
- [semver](https://npm.io/package/semver.md) ^7.3.2
- [terser](https://npm.io/package/terser.md) ^4.6.12
- [core-js](https://npm.io/package/core-js.md) ^3.6.5
- [cssnano](https://npm.io/package/cssnano.md) ^4.1.8
- [find-up](https://npm.io/package/find-up.md) ^4.1.0
- [os-name](https://npm.io/package/os-name.md) ^3.1.0
- [pkg-dir](https://npm.io/package/pkg-dir.md) ^4.2.0
- [resolve](https://npm.io/package/resolve.md) ^1.17.0
- [unixify](https://npm.io/package/unixify.md) ^1.0.0
- [builtins](https://npm.io/package/builtins.md) ^3.0.1
- [g-status](https://npm.io/package/g-status.md) ^2.0.2
- [imagemin](https://npm.io/package/imagemin.md) ^7.0.1
- [inquirer](https://npm.io/package/inquirer.md) ^7.1.0
- [jest-cli](https://npm.io/package/jest-cli.md) ^25.4.0
- [prettier](https://npm.io/package/prettier.md) ^2.0.5
- [username](https://npm.io/package/username.md) ^5.1.0
- [commander](https://npm.io/package/commander.md) ^5.1.0
- [stylelint](https://npm.io/package/stylelint.md) ^13.3.3
- [tty-table](https://npm.io/package/tty-table.md) ^4.1.1
- [babel-jest](https://npm.io/package/babel-jest.md) ^25.4.0
- [css-loader](https://npm.io/package/css-loader.md) ^3.5.3
- [img-loader](https://npm.io/package/img-loader.md) ^3.0.1
- [print-tree](https://npm.io/package/print-tree.md) ^0.1.5
- [san-update](https://npm.io/package/san-update.md) ^2.1.0
- [source-map](https://npm.io/package/source-map.md) ^0.7.3
- [typescript](https://npm.io/package/typescript.md) ^3.8.3
- [url-loader](https://npm.io/package/url-loader.md) ^4.1.0
- [webpackbar](https://npm.io/package/webpackbar.md) ^4.0.0
- [@babel/core](https://npm.io/package/@babel/core.md) ^7.9.0
- [change-case](https://npm.io/package/change-case.md) ^4.1.1
- [file-loader](https://npm.io/package/file-loader.md) ^6.0.0
- [internal-ip](https://npm.io/package/internal-ip.md) ^6.0.0
- [less-loader](https://npm.io/package/less-loader.md) ^6.1.0
- [proxy-agent](https://npm.io/package/proxy-agent.md) ^3.1.1
- [@babel/types](https://npm.io/package/@babel/types.md) ^7.9.5
- [@sentry/node](https://npm.io/package/@sentry/node.md) ^5.15.5
- [autoprefixer](https://npm.io/package/autoprefixer.md) ^9.7.6
- [babel-eslint](https://npm.io/package/babel-eslint.md) ^11.0.0-beta.2
- [babel-loader](https://npm.io/package/babel-loader.md) ^8.1.0
- [loader-utils](https://npm.io/package/loader-utils.md) ^2.0.0
- [postcss-less](https://npm.io/package/postcss-less.md) ^3.1.4
- [style-loader](https://npm.io/package/style-loader.md) ^1.2.0
- [eslint-loader](https://npm.io/package/eslint-loader.md) ^4.0.2
- [imagemin-svgo](https://npm.io/package/imagemin-svgo.md) ^7.1.0
- [monaco-editor](https://npm.io/package/monaco-editor.md) ^0.20.0
- [react-refresh](https://npm.io/package/react-refresh.md) ^0.8.1
- [webpack-merge](https://npm.io/package/webpack-merge.md) ^4.2.2
- [worker-loader](https://npm.io/package/worker-loader.md) ^2.0.0
- [enzyme-to-json](https://npm.io/package/enzyme-to-json.md) ^3.4.4
- [postcss-loader](https://npm.io/package/postcss-loader.md) ^3.0.0
- [@babel/traverse](https://npm.io/package/@babel/traverse.md) ^7.9.5
- [less-plugin-dls](https://npm.io/package/less-plugin-dls.md) ^0.33.4
- [postcss-scopify](https://npm.io/package/postcss-scopify.md) ^0.1.9
- [imagemin-mozjpeg](https://npm.io/package/imagemin-mozjpeg.md) ^8.0.0
- [imagemin-optipng](https://npm.io/package/imagemin-optipng.md) ^7.1.0
- [stealthy-require](https://npm.io/package/stealthy-require.md) ^1.1.1
- [@babel/preset-env](https://npm.io/package/@babel/preset-env.md) ^7.9.5
- [@yarnpkg/lockfile](https://npm.io/package/@yarnpkg/lockfile.md) ^1.1.0
- [classnames-loader](https://npm.io/package/classnames-loader.md) ^2.1.0
- [imagemin-gifsicle](https://npm.io/package/imagemin-gifsicle.md) ^7.0.0
- [sort-package-json](https://npm.io/package/sort-package-json.md) 1.41.0
- [eslint-plugin-jest](https://npm.io/package/eslint-plugin-jest.md) ^23.8.2
- [identity-obj-proxy](https://npm.io/package/identity-obj-proxy.md) ^3.0.0
- [webpack-dev-server](https://npm.io/package/webpack-dev-server.md) ^3.10.3
- [@babel/preset-react](https://npm.io/package/@babel/preset-react.md) ^7.9.4
- [@rollup/plugin-json](https://npm.io/package/@rollup/plugin-json.md) ^4.0.3
- [babel-plugin-import](https://npm.io/package/babel-plugin-import.md) ^1.13.0
- [babel-plugin-lodash](https://npm.io/package/babel-plugin-lodash.md) ^3.3.4
- [copy-webpack-plugin](https://npm.io/package/copy-webpack-plugin.md) ^5.1.1
- [eslint-plugin-babel](https://npm.io/package/eslint-plugin-babel.md) ^5.3.0
- [eslint-plugin-react](https://npm.io/package/eslint-plugin-react.md) ^7.19.0
- [html-webpack-plugin](https://npm.io/package/html-webpack-plugin.md) ^4.2.0
- [react-monaco-editor](https://npm.io/package/react-monaco-editor.md) ^0.36.0
- [regenerator-runtime](https://npm.io/package/regenerator-runtime.md) ^0.13.5
- [rollup-plugin-babel](https://npm.io/package/rollup-plugin-babel.md) ^4.4.0
- [@types/imagemin-svgo](https://npm.io/package/@types/imagemin-svgo.md) ^7.0.0
- [rollup-plugin-eslint](https://npm.io/package/rollup-plugin-eslint.md) ^7.0.0
- [rollup-plugin-terser](https://npm.io/package/rollup-plugin-terser.md) ^5.3.0
- [@ecomfe/eslint-config](https://npm.io/package/@ecomfe/eslint-config.md) ^3.2.0
- [less-plugin-functions](https://npm.io/package/less-plugin-functions.md) ^1.0.0
- [rollup-plugin-postcss](https://npm.io/package/rollup-plugin-postcss.md) ^2.5.0
- [@rollup/plugin-replace](https://npm.io/package/@rollup/plugin-replace.md) ^2.3.2
- [eslint-plugin-reskript](https://npm.io/package/eslint-plugin-reskript.md) ^0.1.2
- [less-plugin-npm-import](https://npm.io/package/less-plugin-npm-import.md) ^2.1.0
- [style-resources-loader](https://npm.io/package/style-resources-loader.md) ^1.3.3
- [@rollup/plugin-commonjs](https://npm.io/package/@rollup/plugin-commonjs.md) ^11.1.0
- [@types/imagemin-optipng](https://npm.io/package/@types/imagemin-optipng.md) ^5.2.0
- [enzyme-adapter-react-16](https://npm.io/package/enzyme-adapter-react-16.md) ^1.15.2
- [eslint-formatter-pretty](https://npm.io/package/eslint-formatter-pretty.md) ^3.0.1
- [mini-css-extract-plugin](https://npm.io/package/mini-css-extract-plugin.md) ^0.9.0
- [webpack-bundle-analyzer](https://npm.io/package/webpack-bundle-analyzer.md) ^3.7.0
- [@babel/preset-typescript](https://npm.io/package/@babel/preset-typescript.md) ^7.9.0
- [@ecomfe/stylelint-config](https://npm.io/package/@ecomfe/stylelint-config.md) ^1.0.0
- [@types/imagemin-gifsicle](https://npm.io/package/@types/imagemin-gifsicle.md) ^5.2.0
- [stylelint-webpack-plugin](https://npm.io/package/stylelint-webpack-plugin.md) ^1.2.3
- [@typescript-eslint/parser](https://npm.io/package/@typescript-eslint/parser.md) ^2.29.0
- [eslint-plugin-react-hooks](https://npm.io/package/eslint-plugin-react-hooks.md) ^3.0.0
- [rollup-plugin-typescript2](https://npm.io/package/rollup-plugin-typescript2.md) ^0.27.0
- [babel-plugin-react-require](https://npm.io/package/babel-plugin-react-require.md) ^3.1.3
- [@rollup/plugin-node-resolve](https://npm.io/package/@rollup/plugin-node-resolve.md) ^7.1.3
- [rollup-plugin-auto-external](https://npm.io/package/rollup-plugin-auto-external.md) ^2.0.0
- [babel-plugin-module-resolver](https://npm.io/package/babel-plugin-module-resolver.md) ^4.0.0
- [monaco-editor-webpack-plugin](https://npm.io/package/monaco-editor-webpack-plugin.md) ^1.9.0
- [babel-plugin-react-css-modules](https://npm.io/package/babel-plugin-react-css-modules.md) ^5.2.6
- [friendly-errors-webpack-plugin](https://npm.io/package/friendly-errors-webpack-plugin.md) ^1.7.0
- [@babel/plugin-syntax-import-meta](https://npm.io/package/@babel/plugin-syntax-import-meta.md) ^7.8.3
- [@typescript-eslint/eslint-plugin](https://npm.io/package/@typescript-eslint/eslint-plugin.md) ^2.29.0
- [@babel/plugin-proposal-decorators](https://npm.io/package/@babel/plugin-proposal-decorators.md) ^7.8.3
- [@babel/plugin-syntax-dynamic-import](https://npm.io/package/@babel/plugin-syntax-dynamic-import.md) ^7.8.3
- [case-sensitive-paths-webpack-plugin](https://npm.io/package/case-sensitive-paths-webpack-plugin.md) ^2.3.0
- [@pmmmwh/react-refresh-webpack-plugin](https://npm.io/package/@pmmmwh/react-refresh-webpack-plugin.md) ^0.3.0-beta.5
- [@babel/plugin-proposal-do-expressions](https://npm.io/package/@babel/plugin-proposal-do-expressions.md) ^7.8.3
- [@babel/plugin-proposal-class-properties](https://npm.io/package/@babel/plugin-proposal-class-properties.md) ^7.8.3
- [@babel/plugin-proposal-numeric-separator](https://npm.io/package/@babel/plugin-proposal-numeric-separator.md) ^7.8.3
- [@babel/plugin-proposal-optional-chaining](https://npm.io/package/@babel/plugin-proposal-optional-chaining.md) ^7.9.0
- [@babel/plugin-proposal-pipeline-operator](https://npm.io/package/@babel/plugin-proposal-pipeline-operator.md) ^7.8.3
- [@babel/plugin-proposal-throw-expressions](https://npm.io/package/@babel/plugin-proposal-throw-expressions.md) ^7.8.3
- [babel-plugin-transform-decorators-legacy](https://npm.io/package/babel-plugin-transform-decorators-legacy.md) ^1.3.5
- [@babel/plugin-proposal-export-default-from](https://npm.io/package/@babel/plugin-proposal-export-default-from.md) ^7.8.3
- [@babel/plugin-proposal-export-namespace-from](https://npm.io/package/@babel/plugin-proposal-export-namespace-from.md) ^7.8.3
- [babel-plugin-transform-react-remove-prop-types](https://npm.io/package/babel-plugin-transform-react-remove-prop-types.md) ^0.4.23
- [@babel/plugin-proposal-nullish-coalescing-operator](https://npm.io/package/@babel/plugin-proposal-nullish-coalescing-operator.md) ^7.8.3

## Recent versions

- 0.26.7 (latest) — 2020-08-09
- 0.26.0-beta.14 (next) — 2020-04-14
- 0.26.0-dev.7 (dev) — 2020-01-29
- 0.26.6 — 2020-07-24
- 0.26.5 — 2020-07-05
- 0.26.4 — 2020-06-11
- 0.26.3 — 2020-06-11
- 0.26.2 — 2020-06-11
- 0.26.1 — 2020-04-27
- 0.26.0 — 2020-04-26
- 0.25.22 — 2020-04-20
- 0.26.0-beta.13 — 2020-04-14
- 0.26.0-beta.12 — 2020-04-14
- 0.25.21 — 2020-04-13
- 0.26.0-beta.11 — 2020-04-13
- … 106 more at https://npm.io/package/reskript/versions

## README

# reSKRipt

基于react与antd技术栈的命令行工具集合。本工具目标整合Lint、Test、Build、Babel、DevServer等一系列功能，使产品线不再重复性地维护复杂的配置文件及相关脚本。

## 关于数据采集

`reskript`默认不进行任何数据的采集，如果支持本工具的开发，可以选择打开。在打开采集后，会采集使用过程中的异常信息，异常信息中将包括：

- 当前操作系统中的用户名。
- 当前操作系统类型和版本。
- 异常发生的详细堆栈，可能由于`webpack`的异常信息，导致包含一部分的源码。
- 使用`reskript`的目标系统的名称，取自`package.json`中的`name`字段。

可以设置`RESKRIPT_TRACK=on`来打开采集功能，如：

```shell
RESKRIPT_TRACK=on skr build
# 或使用更全局的环境变量
# export RESKRIPT_TRACK=on
# skr build
```

## 安装

**要求系统安装`node >= 8.9.0`版本。**

```
npm install --save-dev reskript
```

在安装后，会增加一个`skr`命令。修改项目的`package.json`中的`scripts`部分来增加相关功能：

```
"scripts": {
    "lint": "skr lint",
    "test": "skr test",
    "start": "skr dev",
    "build": "skr build",
    "analyze": "npm run build -- --analyze",
}
```

以上列出了`skr`命令的常用功能，如果有定制化要求（如使用`build.sh`代替简单的`skr build`），则同样可以调用这些命令完成工作。

## 自动生成配置文件

使用`skr satisfy`自动在项目中添加需要的配置文件，并安装相关的依赖。

```
Usage: satisfy [options]

Satisfy project dependencies

Options:
  --ts            whether this is a typescript project
  --type [value]  your package type, either "app" or "lib" (default: "app")
  --ut [value]    environment of unit test, "node" or "react" (default: "node")
  -h, --help      output usage information
```

初始化会为项目添加以下内容：

- 添加`webpack.config.js`用于WebStorm解析路径，注意这个配置文件不用于实际的构建，仅供IDE参考。
- 添加`eslint`的配置，指向reskript指定的规则。
- 根据`--ts`参数，添加`tsconfig.json`或`jsconfig.json`。
- 根据`--webpack`参数自动安装`webpack`的依赖。
- 如指定`--ut=react`，则自动安装`enzyme`。

如果已经手工完成以上步骤，则无需运行此命令进行初始化。

## 检查代码

使用`skr lint`检查代码规范。

```
Usage: lint [options] [files...]

Lint files, by default .js(x) files under src and webpack are linted

Options:
  --changed                    lint only changed files in git workspace
  --staged                     lint only staged (both partially and fully) files in git workspace
  --allow-unsafe-react-method  allow UNSAFE_* methods in react component
  --fix                        fix possible lint errors
  -h, --help                   output usage information
```

对于新项目，建议直接使用`skr lint`检查整个项目。遗留项目可以使用`skr lint --changed`仅检查修改过的文件。同时在Git的`pre-commit`钩子上使用`skr lint --staged`来保证入库的代码是符合规范的。

## 测试

使用`skr test`测试。

```
Usage: test [options]

Test

Options:
  --cwd [value] override current working directory (default: process.cwd())
  --coverage  indicates test coverage information
  --watch     watch files for changes and rerun tests related to changed files
  --target [value] specify test environment of the project is "react" or "node" (default: "node")
  --changedSince [value] runs tests related to the changes since the provided branch. (default: '')
  -h, --help  output usage information
```

`skr test`会自动搜索所有 .test.js 结尾的文件运行，建议的文件结构为

```
/__tests__
    * util.test.js
util.js
```

然后在 util.test.js

```
import {add} from '../util';

describe('add', () => {
    test('1 + 2 = 3', () => {
        expect(add(1, 2)).toBe(3);
    })
})
```

CHANGE:
0.25.17 之后

1. 不再支持相对路径的src目录参数，resolve src只是cwd下面的src目录。影响是：只可以在eefe root目录级别运行skr test，才能正确resolve @/ 到 src/ 下面

2. 添加了根据项目里的jest.config.js来配置jest的能力。
- 如果项目中有jest.config.js，需要指定reskript/config/jest-react.js的**相对路径**（根据当前项目）来引入skr test的默认配置。例如：'./node_modules/reskript/config/jest-react.js'。 如果使用require.resolve('reskript/config/jest-react.js')，需要变成相对目录，`'./' + path.relative('', require.resolve('reskript/config/jest-react.js'))`， 前面的 `./` 是需要的。
如果是react，引用`jest-react.js`，如果是node，引用`jest-node.js`。
- 如果项目中没有jest.config.js，skr test会用默认配置（与preset相同）
**注意**： 如果用了jest.config.js，settings下面的test值将不起作用。

## 实时预览组件

使用`skr play`可以打开一个实时编辑页面，用于测试及预览指定的组件。

```
Usage: play [options] <target>

Start a playground to debug a certain component

Options:
  --cwd [value]           override current working directory (default: process.cwd()")
  --build-target [value]  set build target, default to "dev" (default: "dev")
  -h, --help              output usage information
```

如执行`skr play src/components/UserInfo/index.js`后，则会进行自动构建，随后可在`http://localhost:9999`中打开实时预览页面，页面左侧可编辑代码，右侧进行实时的预览。

## 打包基础库

使用`skr rollup`来对基础库（非业务系统）进行打包，底层使用[rollup](https://rollupjs.org/)实现。

```shell
Usage: rollup [options]

Build entire app

Options:
  --cwd [value]   override current working directory (default: process.cwd())
  --mode [value]  set build mode, default to "production" (default: "production")
  --clean         remove dist directory before build
  -h, --help      output usage information
```

可以在`settings.js`中导出`rollup`对象，允许有以下属性：

- `{Object} namedDependencyExports`：指定第三方库的命名导出，具体参考[rollup-plugin-commonjs的说明](https://github.com/rollup/rollup-plugin-commonjs#custom-named-exports)。
- `{string} styleOutput`：指定样式的输出格式，为`"inject"`时内置到JavaScript中，为`"extract"`时输出为与JavaScript同名的`.css`文件，为`"index"`时输出为单个`style/index.css`文件，默认值为`"index"`。
- `{string} target`：指定编译的目标平台，为`"web"`、`"node"`或`"universal"`，默认为`"universal"`。指定`"web"`时仅用于浏览器，但可以基于此做一些优化，如移除node模块的依赖。

除此以外，当前版本不暴露任何配置，封闭了`eslint`、`babel`、`postcss`等能力。

## 构建系统

### 基础目录结构

构建系统对目录结构有一定要求，必须包含以下部分：

```
/src
    /styles
        *.global.less # .global.less文件不会经过CSS Modules编译，可放置一些全局的样式
        *.var.less # .var.less会被提取作为LESS编译时的变量，内部仅可声明变量（以及注释）
    /entries
        index.js # 主入口
settings.js # 系统配置文件
```

其中`*.global.less`事实上可以放置在任意位置，只要是以`.global.less`结尾的，均不会经过CSS Modules处理。

默认`.less`文件内可直接使用[EST插件](http://ecomfe.github.io/est)提供的内容，其它相关loader的配置请直接参考源码，不再赘述。

#### 特殊文件命名

以下是可用的一系列特殊处理的文件命名规则：

- `*.global.less`：定义全局的样式，不会经过CSS Modules处理。
- `*.worker.js`：定义Web Worker，会被编译成一个Worker类。

### 全局变量

在源码中可以使用以下的全局变量（通过`DefinePlugin`提供）：

- `process.env.XXX`：对应环境变量中的值。
- `$features.xxx`：对应Feature Matrix中的特性值。
- `$build.mode`：构建时的`mode`值，建议使用这个变量来代替`process.env.NODE_ENV`。
- `$build.version`：当前构建的版本号。
- `$build.target`：当前构建的目标。
- `$build.time`：当前构建的时间，为ISO格式字符串。

以上全局变量可直接使用，不会被`lint`功能认为错误。

### 系统配置

对于业务系统，必须在项目根目录下放置一个`settings.js`，该文件为项目的整体配置，需导出`featureMatrix`、`build`、`devServer`、`addition`及`plugins`共五项。基础库也可通过`settings.js`（可选）导出`rollup`用于第三方库的构建，但与系统的构建无关，参考前文：

#### Feature Matrix

除第三方库类型的项目外，要求所有系统使用Feature Matrix维护源码，避免Feature分支开发导致的合入困难问题。

由`settings.js`导出`featureMatrix`对象，该对象的每一个属性均代表一个Feature集合。

一个项目必须至少包含以下3个Feature集合：

- `stable`：用于全流量。
- `insiders`：用于小流量。
- `dev`：用于开发。

以上3个集合为必须，其中`dev`仅在开发过程使用。如果系统本身没有灰度机制，可以使用最简单的模板：

```javascript
exports.featureMatrix = {
    stable: {},
    insiders: {},
    dev: {}
};
```

#### 构建配置

由`settings.js`导出`builld`对象，可以包含以下属性：

- `{boolean} thirdParty`：是否以第三方库的形式构建，第三方库的构建不使用`featureMatrix`、不拆分chunk，同时构建产出不带hash、不产出HTML文件。
- `{boolean} reportLintErrors`：构建过程中检查代码规范，默认值为`true`。如无特殊原因，禁止关闭这个开关。
- `{boolean} extractCSS`：是否将CSS抽取到独立的`.css`文件中，默认为`true`，当CSS的顺序有问题，或者构建第三方库时，可以选择设置为`false`。
- `{Condition} noCompileScripts`：无需经过babel编译的JavaScript文件列表，仅包含项目源码部分，不要包含第三方的库。
- `{Condition} noModulesStyles`：无需经过CSS Modules处理的样式文件列表，仅包含项目源码部分，不要包含第三方的库。如果整个系统没有使用CSS Modules，则该配置的值可以为`[() => true]`。
- `{string[]} styleResources`：用于编译LESS的变量资源文件列表。每个文件均会被注入到所有的LESS文件前面，作为全局可用的资源。
- `{number} largeAssetSize`：生成静态文件的限值，以字节为单位。小于该值的会被编译为DataURI内联，大于该值的会变为单独的文件。默认值为`8KB`。
- `{Object} browserSupport`：支持的浏览器范围，用于[babel-preset-env](https://github.com/babel/babel/tree/master/packages/babel-preset-env)。
- `{boolean} styleName`：是否使用`styleName`来调用CSS Modules，默认为`true`。
- `{boolean} polyfill`：是否自动引入`core-js`的相应polyfill，默认为`true`。如果你使用了其它方式引入polyfill，设置为`false`即可。
- `{string} extraLessPaths`：LESS中`@import`的查找路径，默认为`src`, `node_modules`, `src/styles`这三个目录。
- `{string} cssScope`：给所有的CSS选择器加上一个作用域，如该属性值为`#foo`，则`header > .navigation`会变为`#foo header > .navigation`。
- `{Object[]} copies`：需要进行复制的静态文件列表，用于[copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin)。
- `{string} appTitle`：应用的标题，用于生成`<title>`元素。
- `{string} favicon`：favicon的位置。
- `{string[]} excludeFeatures`：构建过程中需要排除的Feature名称，默认排除`['dev']`，其它均会被构建。
- `{boolean} autoRouteSplit`：自动根据路由进行code split，具体参考[自动路由拆分](#自动路由拆分)章节。

#### 调试服务器

由`settings.js`导出`devServer`对象，可包含以下属性：

- `{number} port`：启动的端口。
- `{string[]} apiPrefixes`：需要代理的API请求的前缀，如`['/rest', '/api']`则会将所有`/rest`或`/api`的请求代理至后端。
- `{string} defaultProxyDomain`：默认的后端域名，仅需填写域名部分（如`engmapbeta.baidu.com`），可以被`--proxy-domain`参数覆盖。
- `{string} hot`：是否启用HMR，可选值为`none`、`simple`或`all`。使用`none`时禁用HMR；为`simple`时开启简单的HMR，仅对样式等资源生效；为`all`时开启`hotOnly`配置，并自动打开React的HMR。

#### 入口页配置

构建或调试允许定制入口页，也允许单系统多入口。

系统必须有`src/entries`这个目录，其下放置所有的入口文件，默认的名称为`index`。每一个入口对应以下文件：

- `[name].js`：入口的启动脚本。
- `[name].ejs`：HTML模板，以EJS作为模板格式，如果一个入口不存在对应的`.ejs`文件，则会使用默认的模板。自定义模板可使用`htmlWebpackPlugin.options.buildIdentifier`获取构建版本号。
- `[name].config.js`：生成入口页面的额外配置，这个文件的`module.exports`对象会直接传递给[html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin)，可以定制化页面信息，也可以将额外的数据传递给`[name].ejs`模板。

例如某个入口页面的`<title>`希望得到修改，则可以在`[name].config.js`中这样写：

```javascript
module.exports = {
    title: '定制化的标题'
};
```

入口页的模板（`[name].ejs`）或配置文件（`[name].config.js`）修改后，**需要手动重启调试**，当前版本并不会自动监听这些文件。

#### 额外配置

由`settings.js`导出`addition`函数，该函数将接受一个构建时的环境对象，并返回一部分webpack配置。

**当由`addition`函数返回的配置中包含`module.rules`时，自定义的`module.rules`将完全覆盖默认的配置（不会做任何的合并策略）**，其它的配置项则会通过[webpack-merge](https://github.com/survivejs/webpack-merge)与默认的配置合并。

所谓构建时的环境对象，即通过`build`导出的对象，外加通过命令行提供的参数。通常来说，其中的`mode`属性是最为重要的。

#### 默认配置

以下为一个常见的默认配置，仅供参考：

```javascript
exports.featureMatrix = {
    stable: {},
    insiders: {},
    dev: {}
};

exports.build = {
    appTitle: 'React App', // 修改为应用的名称
};

exports.devServer = {
    port: 8078, // 修改为不与其它应用重复的端口号
    apiPrefixes: ['/api'],
    defaultProxyDomain: '', // 修改为测试环境地址
    uuapCallbackURL: '/',
    presetUsers: [] // 添加模块登录的预置用户
};

exports.addition = () => ({});
```

#### 使用插件

由`settings.js`导出`plugins`数组，数组中的每一项为一个函数，函数接受`settings.js`导出的`{featureMatrix, build, devServer, addition}`对象和当前命令行参数，并返回一个相同的对象。

插件会按顺序被依次调用，最终返回的对象用于各种功能。

### 构建产物

构建输出到`dist`目录，所有静态资源放置于`dist/assets`目录下，入口HTML页面放置于`dist`目录下。基于Feature Matrix进行构建后，不同Feature集产生的文件也都混合在一起，无需分隔为不同目录。

在Feature Matrix的模式下，线上分流需要按照HTML文件名分流，如主流量分到`stable.html`上，小流量则分到`insiders.html`上。而`dist/assets`目录则不需要设置鉴权，以便Sentry或Firefox等应用在无Cookie的情况下可以成功下载到Source Map。

如果当前系统线上无法基于HTML文件名分流，则参考“启动构建”章节使用`--build-target`参数进行兼容。

### 启动构建

使用`skr build`构建整个系统。

```
Usage: build [options]

Build entire app

Options:
  --cwd [value]           override current working directory (default: process.cwd())
  --mode [value]          set build mode, default to "production" (default: "production")
  --src [value]           specify the dir containing source files relative to cwd (default: "src")
  --build-target [value]  create index.html according to specific target
  --analyze               enable bundle analysis
  --clean                 remove dist directory before build
  -h, --help              output usage information
```

默认基于Feature Matrix构建，需要线上的Nginx等服务器配合分流。如果没有这一能力，则需要指定`--build-target`参数，该参数指定的Feature集合的构建结果会被复制为`index.html`，以便上线部署时不会出错。

### 打开调试服务器

使用`skr dev`启动调试服务器，初次构建完成后会自动打开网页。

```
Usage: dev [options]

Start dev server for debugging

Options:
  --cwd [value]            override current working directory (default: process.cwd())
  --mode [value]           set build mode, default to "development" (default: "development")
  --src [value]            specify the dir containing source files relative to cwd (default: "src")
  --build-target [value]   set build target, default to "dev" (default: "dev")
  --proxy-domain [domain]  set api proxy domain, only domain part (www.example.com) is required
  -h, --help               output usage information
```

在调试过程中，会监听`settings.js`的变更并重启调试服务器，重启后不会自动打开网页。

### 自动路由拆分

当`settings.js`中的``exports.build.autoRouteSplit`属性为`true`时，会启用自动路由拆分，该逻辑会找到合适的拆分点，要求需要满足以下条件：

1. 组件被使用在`<TrackRoute components>`属性上，如`<TrackRoute exact path="/admin" components={AdminPage} />`。
2. 对应的组件必须是默认引入的，即`import AdminPage from '../AdminPage'`的形式。
3. 必须配合[@ecomfe/react-track](https://www.npmjs.com/package/@ecomfe/react-track)使用。

在满足以上条件时，如下代码：

```javascript
import AdminPage from '../AdminPage';

<TrackRoute exact path="/admin" component={AdminPage} />
```

会被编译为：

```javascript
import {lazy} from 'react';

const LazyAdminPage = lazy(() => import('../AdminPage'));
<TrackRoute exact wrapSuspense path="/admin" component={LazyAdminPage} />
```

以此获得webpack的code split能力。由于`lazy`后的组件必须搭配`Suspense`使用，所以依赖`@ecomfe/react-track`的`TrackRoute`组件支持（内部自动添加`Suspense`）。

**当前无法保证此功能100%满足场景，开启后请小心测试。**

### 定制化构建

如果默认的构建配置外加`settings.js`无法满足，或需要在`settings.js`中的`addition`部分复用一些默认的配置，则可以使用`reskript`提供的函数辅助创建loader相关的配置。

#### 复用loader

`reskript`导出`loaders`对象，内含了生成常用loader配置的函数，包括：

- `babel({cwd, mode, browserSupport, ui, styleName})`
- `css({mode})`
- `cssModules({mode})`
- `eslint({mode})`
- `less({mode, cwd, extraLessVariables, extraLessPaths})`
- `postCSS({mode, cssScope, lint}, {external = false} = {})`
- `styleResources({cwd})`
- `sourceMap()`
- `style({mode})`
- `img({mode})`
- `url({largeAssetSize})`
- `typescript({mode})`

以上函数的相关配置均参考构建配置的对应字段。

#### 复用规则

如果在复用loader的情况下，还希望复用`module.rules`的相关规则，`reskript`导出`rules`对象，包括：

- `script(env)`
- `less(env)`
- `css(env)`
- `image(env)`
- `file(env)`
- `typescript(env)`

以上函数均需要一个完成的配置对象（`env`）作为参数，该对象即`settings.js`中的`addition`函数接收的参数。

对于需要修改某一个规则的情况，建议在`rules`的基础上移除需要修改的规则后全部应用，再增加自定义规则。如某个项目需要将`.css`文件的规则修改，则可以如下配置：

```javascript
const {omit} = require('lodash');
const {rules} = require('reskript');

exports.addition = env => {
    // 先移除css的规则
    const baseRules = Object.values(omit(rules, ['css'])).map(rule => rule(env));

    return {
        module: {
            rules: [
                ...baseRules,
                {
                    test: /\.css$/,
                    use: [...]
                }
            ]
        }
    };
};
```

`reskript`无法保证每一次升级时在`rules`对象上保持完全的向后兼容，如上的写法可比较灵活地应对升级导致的规则的增减。

## 获取webpack配置

为了方便与其它工具如[react-styleguidist](https://github.com/styleguidist/react-styleguidist)进行整合，`reskript`允许通过程序获取webpack的配置。使用`createBuildConfig(env)`及`createDevConfig(env)`函数分别获取完整构建或者开发调试用的配置对象。

其中`env`对象必需包含以下属性：

- `{Object} projectSettings`：来自`settings.js`的对象，通常使用`require('./settings')`获取即可，具体结构见前文描述。
- `{string} mode`：构建的形式，为`development`或`production`。
- `{string} usage`：构建使用场景，为`build`（构建产出结果）或`devServer`（开发调试服务器）。

其它可选属性参考`build`及`dev`命令的帮助文档，所有命令行参数均可在`camelCase`化后作为`env`对象的属性传入。

## 辅助排查

当`skr`命令出现不符合预期的问题时，它很有可能是因为间接依赖的第三方包导致的。由于`reskript`并不使用shrinkwrap机制锁定版本，因此需要导出所有第三方依赖的版本来确定问题。使用`skr doctor`可以得到排查问题的相关信息：

```
Usage: doctor [options]

Collect debug information for et itself

Options:
  --cwd [value]  override current working directory
  --json         print result in JSON format
  -h, --help     output usage information
```

通常使用`skr doctor | pbcopy`可将结果复制到剪贴板中。

对于新项目，建议直接使用`skr lint`检查整个项目。遗留项目可以使用`skr lint --changed`仅检查修改过的文件。同时在Git的`pre-commit`钩子上使用`skr lint --staged`来保证入库的代码是符合规范的。

## TODO

- 支持DLL：等autodll-webpack-plugin升级后实现。

---
_Source: https://npm.io/package/reskript · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
