reskript
v0.26.7
Published
Finely maintained scripts for react libs and apps
Downloads
95
Readme
reSKRipt
基于react与antd技术栈的命令行工具集合。本工具目标整合Lint、Test、Build、Babel、DevServer等一系列功能,使产品线不再重复性地维护复杂的配置文件及相关脚本。
关于数据采集
reskript
默认不进行任何数据的采集,如果支持本工具的开发,可以选择打开。在打开采集后,会采集使用过程中的异常信息,异常信息中将包括:
- 当前操作系统中的用户名。
- 当前操作系统类型和版本。
- 异常发生的详细堆栈,可能由于
webpack
的异常信息,导致包含一部分的源码。 - 使用
reskript
的目标系统的名称,取自package.json
中的name
字段。
可以设置RESKRIPT_TRACK=on
来打开采集功能,如:
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 之后
不再支持相对路径的src目录参数,resolve src只是cwd下面的src目录。影响是:只可以在eefe root目录级别运行skr test,才能正确resolve @/ 到 src/ 下面
添加了根据项目里的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实现。
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的说明。{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插件提供的内容,其它相关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
仅在开发过程使用。如果系统本身没有灰度机制,可以使用最简单的模板:
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。{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。{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,可以定制化页面信息,也可以将额外的数据传递给[name].ejs
模板。
例如某个入口页面的<title>
希望得到修改,则可以在[name].config.js
中这样写:
module.exports = {
title: '定制化的标题'
};
入口页的模板([name].ejs
)或配置文件([name].config.js
)修改后,需要手动重启调试,当前版本并不会自动监听这些文件。
额外配置
由settings.js
导出addition
函数,该函数将接受一个构建时的环境对象,并返回一部分webpack配置。
当由addition
函数返回的配置中包含module.rules
时,自定义的module.rules
将完全覆盖默认的配置(不会做任何的合并策略),其它的配置项则会通过webpack-merge与默认的配置合并。
所谓构建时的环境对象,即通过build
导出的对象,外加通过命令行提供的参数。通常来说,其中的mode
属性是最为重要的。
默认配置
以下为一个常见的默认配置,仅供参考:
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`时,会启用自动路由拆分,该逻辑会找到合适的拆分点,要求需要满足以下条件:
- 组件被使用在
<TrackRoute components>
属性上,如<TrackRoute exact path="/admin" components={AdminPage} />
。 - 对应的组件必须是默认引入的,即
import AdminPage from '../AdminPage'
的形式。 - 必须配合@ecomfe/react-track使用。
在满足以上条件时,如下代码:
import AdminPage from '../AdminPage';
<TrackRoute exact path="/admin" component={AdminPage} />
会被编译为:
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
文件的规则修改,则可以如下配置:
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进行整合,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升级后实现。