Git Product home page Git Product logo

reskript's Introduction

基于 React 与 Ant Design 开发的命令行工具套件

本文档对应6.x版本,如果你使用其它版本,请参考升级手册进行升级。

6.x版本对应antd 5.x,如果你使用4.x版本,请参考第三方库优化进行配置。

reSKRipt 是基于 ReactAnt Design 开发的一套命令行工具套件,整合了代码检查、单元测试、构建、代码转义和本地调试等一系列功能,意图做到在开发业务时无需关心工具选型。

快速开始

mkdir my-app
npx @reskript/init@latest my-app
cd my-app
npm start

进一步的使用欢迎参考使用文档

为什么自研

社区中的 create-react-app 提供了最基础的开发体验,而 reSKRipt 则在此基础之上加了一些独特的能力和更多的约束,在此例举一些主要的:

  • 更严格地挑选 Babel 插件:我们曾经在 bind operator 标准上吃过不小亏,从此以后便开始避免无脑地使用 stage-0 来进行转义,精细地挑选当前的插件,选择更为成熟且比较确定会持续演进最终进入规范的部分。
  • 默认 CSS Modules:所有的 .less 和 .css 文件均经过 CSS Modules 处理,仅有 .global.{less,css} 被排除在外,这能够更好地控制样式的隔离,更符合一个严谨的工程开发模式。
  • 样式被转化为函数:对于样式文件,在引入后会变成一个函数,比如: import c from './index.less' 后可以使用 c('text', {'size-small': props.small}) 这样的形式生成元素的className,内部基于 classnames 实现。
  • SVG组件化:可以通过 import ReactComponent from './icon.svg?react' 将 SVG 转化为组件,这与 create-react-app 提供的能力相似,但 reSKRipt 使用了自定义的 loader 来实现这一功能,具备更好的转换性能。
  • 严格的代码检查规则:基于百度内部的编码规范,使用 @ecomfe/eslint-config@ecomfe/stylelint-config 的严格规则做检查,并在此基础上增加了一系列自己的规则,代码检查远比社区更加严格。
  • 自动添加组件名称:所有组件都会自动加上 displayName 属性,无论是以 function、const 还是 export default 定义,都能很好地识别出来并自动的推导最合适的组件名称。
  • 追求更新的框架版本:仅支持 react@17 和 webpack@5,并且我们在未来也将以最快速度跟进框架的最新版本,不断淘汰对旧版本的支持,以此让业务紧密跟随社区的发展。
  • 更低成本地升级工具:统一封装Vite、Webpack等底层工具链,便于社区向前走时及时的跟上切换。

因此,使用 reSKRipt 可能会一定程度上约束你的开发模式,它并不一定适用于所有的应用,但我们有信心在开发模式契合的情况下为你大幅度提升开发效率。

版本管理

所有的包始终使用同一个版本,由 lerna 进行管理,使用 pnpm 作为包管理工具。

我们会在发布版本的时候使用 --force-publish 参数,这意味着即便有一个包没有任何的改动,也会跟随发布新的版本。这样做的好处是能很好地处理各包之间错综复杂的依赖关系,避免某个包被重复引入多个版本。

如果你需要升级包,在知道最新版本号的前提下,大可以在 package.json 文件中把所有以 @reskript/ 开头的包的版本统一修改,再运行 npm installyarn 来更新。

安装

要求系统安装node >= 14.0.0版本。

一些你基本上一定会需要的依赖,任何场景都请先安装上:

npm install -D eslint stylelint typescript webpack

reSKRipt 由多个包组成,你可以按照下面描述的不同场景选择性安装:

  • 我想用 webpack 构建我的应用
npm install -D -E @reskript/cli @reskript/cli-build

skr build
  • 我想用 webpack-dev-server 调试我的应用
npm install -D -E @reskript/cli @reskript/cli-dev

skr dev
  • 我想基于已有的 webpack 配置自己定义构建
npm install -D -E @reskript/config-webpack
  • 我想检查我的代码规范
npm install -D -E @reskript/cli @reskript/cli-lint

skr lint
  • 我直接使用 eslint、通过 vscode 的 eslint 插件检查代码,但想使用已有的规则配置
npm install -D -E @reskript/config-lint
  • 我想用jest 进行单元测试
npm install -D -E @reskript/cli @reskript/cli-test

skr test
  • 我想基于已有的 jest 配置进一步定制我的单元测试
npm install -D -E @reskript/config-jest

reskript's People

Contributors

btnkr avatar crayonn avatar dancerphil avatar dongggcom avatar gxy01 avatar lefex avatar leotian avatar leuisken avatar lirunnan avatar mbearo avatar meerkat-morecats avatar mzvast avatar otakustay avatar suica avatar symind avatar yhkk1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

reskript's Issues

项目初始化能力

总的来说,要手动判断怎么安装一大堆的包还是太麻烦了,我们需要一个初始化的工具,类似用法:

npx @reskript/init my-app

大致作用:

  1. 询问需要的能力(比如要不要编译、要不要单测之类的)
  2. 根据回答安装上相关的依赖
  3. 在用户需要的情况下,初始化一个简单的模板,特别针对src/entries这个特殊点,也包括所有需要的配置文件

整理所有情况的退出码

现在process.exit用的退出码用得非常随意,无法用退出码来确定具体的错误情况,要整体梳理一下,并在文档中把所有退出码和原因列出来

less-safe-loader没处理好嵌套的括号

  • 输入:padding-right: calc(@drawer-header-close-padding - var(--scroll-bar))
  • 期望输出:padding-right: ~'calc(@drawer-header-close-padding - var(--scroll-bar))'
  • 实际输出:padding-right: ~'calc(@{drawer-header-close-padding} - var(--scroll-bar)')

最后的')位置错了

finalize的属性安全

按照现在reSKRipt的实现,是无法保证一些经常要被覆盖的webpack配置属性在finalize中一定存在的,所以容易出现这样的代码:

finalize = webpackConfig => {
    webpackConfig.plugins = webpackConfig.plugins ?? [];
    webpackConfig.plugins.push(...);
};

为了保证属性存在,会需要一些额外的代码,这很没意思。所以让reSKRipt生成最初的配置时,把一些常用的属性保证好:

  • plugins
  • module.rules
  • resolve.alias
  • optimization

同时文档也要更新相关说明

指定构建的入口

现在的reSKRipt会自动收集src/entries下的所有入口文件做多入口的构建。有些项目会从子项目的维度来分割入口,则可能只需要构建某一个入口

可以参加一个--entries-only参数指定需要构建的入口,支持逗号分隔的多个

对finalize的返回结果做校验

在实践中,经常发现各种finalize函数内忘了最后返回配置对象,导致工具内部拿到了一个undefined对象出错。

可以给finalize调用增加返回值校验,发现是undefined的时候增加一个友好的报错。

迁移到ESM上

根据这个更新纪要,社区有大量的库正在向纯ESM的方向发展,编译为CommonJS的reSKRipt不跟上的话会无法继续使用社区最新的成果

使用ESM会需要Node >= 12,在近期版本中先加上这一限制

已知当前升级到了ESM不再兼容CommonJS的库,这些库以后不能再继续升版本了

  • imagemin
  • log-symbols

我们需要做的:

  • 给CLI设定要求Node在12以上
  • import加上文件后缀名,保持全路径
  • 把所有动态的require干掉,可以异步的就用await import,不可以的就做成静态import。这可能会因为增加过多的import导致初始化性能有所下降,要做一次测试
  • 干掉__dirname__filename,转用import.meta.url处理
  • require包在ESM下工作不符合预期,用@reskript/coreresolveSync替换
  • 如果有import 'xxx.json'的情况,改用fs.readFile处理
  • 研究下ESM和bin是不是兼容,是否能直接执行
  • 要求reskript.config.js变为reskript.config.mjs并使用类似export const build = {}的形式编写配置
  • 研究下jest的配置怎么去解析,现在用的是require('jest.config.js')
  • 加上相关的eslint规则避免错误地使用require
  • 关于reskript.config.js的多次加载,可以用import 'reskript.config.js?v=xxx'这种形式来实现,但可能用久了内存会爆,需要小心:nodejs/node#49442

一些社区相关的需要解决的问题:

支持skr dev指定某个入口

如果一个项目有多个入口,只有index现在是默认被当成history fallback来用的,其它的都不行,这会导致很难访问到其它入口(/assets/xxx.html几乎没人知道),且访问到了因为有basename不同的问题,内部路由也无法正常工作

所以考虑加一个skr dev --entry=xxx这样的参数来支持指定入口调试

接管publicPath

基于webpack的配置说明publicPath可以是运行时动态的,这意味着如果reSKRipt可以接管这个配置,并且对生成的HTML做一些手脚,插入个<script>啥的,可以玩出很多运行时的警花样来,比如用相同的构建,但在构建完成后改HTML来适配有CDN的线上环境和无CDN的线下环境

所以直接在reskript.config.js中的build里加一个publicPath参数就行

less calc修复功能

在不少第三方(甚至自己写的)的.less文件中,会有这样的:

width: calc(100px - @min-height);

这种写法默认是没有问题的,但在less 4.x下,配合类似less-plugins-functions这种极端hack的插件时,就会出大问题。

正确的写法需要是~"calc(100px - @{min-height})"。所以让reSKRipt内置一个功能,把所有不安全的calc都修复一下。

暴露一些内部依赖给finalize

比如在build.finalize中,如果想额外生成一个HTML文件,就需要用户自己装html-webpack-plugin,但进一步又可能因为装的版本不一样产生不可预期的行为。

为此,把一些内部的依赖通过函数的参数给出去,变成这样的代码:

const finalize = (webpackConfig, internals) => {
    const {HTMLWebpackPlugin} = internals;
    webpackConfig.plugins.push(new HTMLWebpackPlugin(...));
    return webpackConfig;
};

skr play支持自定义wrapper结构

比如你要调试一个返回的是Fragment的组件,它原本是被预期放在一个display: flex的容器里的。但skr play默认不会搞出这种容器,所以左右结构就会变成上下结构

image

计划提供这样的配置,在reskript.config.js里:

exports.play = {
    wrapper: `
        <div style={{display: 'flex'}}>
            {children}
        </div>
    `
};

其中wrapper会被编译成一个LayoutWrapper的组件的返回部分,仅支持children这一个属性。

不让指定完整的逻辑是考虑到JS逻辑注入的安全性太差,不敢乱来。

把play功能找回来

原本内部版本是有skr play功能的,因为monaco-editor-webpack-plugin的兼容问题删掉了。现在兼容问题应该解决了,所以可以找回来。

当然原来版本打开的页面太丑了,最好找个简单的设计稍微美化一下。

默认HTML模板支持生成一个带id的应用容器

现在大部分应用,对初始HTML要求就是一个<div id="root"></div>,这个id要自己指定

最初我们是想不要有这么个容器,直接document.body.appendChild(document.createElement('div'))就行了,但好像和微服务整合的时候不行,所以得加这功能

init支持gerrit兼容

因为gerrit使用commit-msg这个钩子,而如果用husky@6的话,默认会冲掉钩子(哪怕你实际没有commitlint之类的东西)

所以如果需要gerrit兼容,则安装husky@4并配置package.json

加一个doctor功能

reSKRiptcreate-react-app多多少少有些不一样,比如对目录结构要求、对依赖的要求等,做一个npx @reskript/doctor功能来检查一下。

  • 目录结构有src/entries
  • 依赖装了eslintstylelinttypescriptwebpack
  • 所有@reskript/*的包版本相同
  • 要支持monorepo

增加CLI的Node版本限制

找个时机发一个没有任何新功能和bug修复的版本,仅仅为@reskript/cli加上Node版本限制

版本限制最小为v14.13.1,这个版本同时支持ESM和node protocol

支持近前缀设置devServer的代理

但这容易和defaultProxyDomain参数冲突,所以考虑增加一个proxyRewrite配置,可以使用对象的形式:

proxyRewrite: {
  '/xxx': 'remote-host.com/yyy',
}

proxyRewrite会优先于apiPrefixes处理,本身有完整的代理配置能力。在apiPrefixes中但没有在proxyRewrite中的,走defaultProxyDomain

收集FAQ

作为一个封装了大量功能的工具集,在实际使用中肯定会出现“某某情况要怎么办”这样的疑问。借这个议题收集大家的问题,后续会一一更新到文档的FAQ章节中。

给build增加一个strict参数

虽然不知道能干啥,但先加一个,控制未来的严格校验

可能可以有的:

  • import的大小写校验
  • import的路径校验,比如只能在srcnode_modules
  • 关掉对require.ensure的支持
  • 对ESM检查是否和package.json中的声明一致

当然我们一定是推荐用--strict

支持异步插件

plugins中的插件可以异步地更新配置,理论上具备可行性

calc(~"100vh - @{top}") 报错

现在calc(~"100vh - @{top}") 会被替换成 ~'calc(~"100vh - @{top}")', 导致编译到postcss-loader时候报错。
希望能替换成 ~'calc(100vh - @{top})'

顺便提一下calc(~'100vh - @{top}') 这样的话估计也有问题

引导用户不要修改webpack.config.js

reSKRipt生成的webpack.config.js只是给IDE识别alias用的,修改它并不会改变构建效果,但不少用户并不了解这一点,所以需要加一些说明

bundle分析功能

先收集一波可行的策略

  • 初始加载资源分析
    • 资源数量
    • 资源总体积
    • 资源平衡性(不同资源间尺寸不要差距过大)
    • 拒绝某些包初始加载(如要求首屏不引入echarts
  • 多次构建的产出差异和趋势
    • 资源体积
    • 哈希稳定性
  • 依赖锁过期情况
  • 同库多版本引入情况
  • 需要tree shaking的库通过bundle引入的情况

支持service worker的构建

PWA场景里,希望service-worker.js. manifest.json 等文件没有hash,且可以使用skr中的一些变量,比如$build,来描述service-worker的版本。

直接使用babel编译文件的功能

现在越来越多的lib已经不需要rollup之类的打包了,直接转一下babel发布就行。可以提供一个@reskript/cli-babel包来支持:

skr babel --out=dist src/

可以的功能:

  1. 使用内置的babel配置转换每一个文件。
  2. 支持指定输出目录。
  3. 支持把非JS的文件直接复制过去,比如.less之类的。

支持在入口自定义webpack的entry配置

当前reSKRipt的策略是,每一个入口可以配一个xxx.config.js文件,但里面只能导出html-webpack-plugin的配置

有一种场景是,不同的入口需要有不同的产出格式,比如有些入口不要产生hash,有些则要构建成CJS等

为此,我们要扩展一下xxx.config.js的职能,保留现在兼容性的基础上,增加以下逻辑:

  1. 如果导出包含了entryhtml这2个属性,则认为是新的对象结构
  2. 在新的对象结构中,html-webpack-plugin的配置要求放在exports.html
  3. 可以使用exports.entry配置webpack entry

后续在2.0版本中,可以把旧格式的支持删除

发布1.0到正式版

因为一系列peer依赖导致的NPM 7兼容问题,现在始终用着beta的标签。但这样下去会频繁出现安装时没有指定@next导致的各类问题

从社区的反馈来看,所有的包兼容到NPM 7不是一个短时间能搞定的事情,所以考虑就直接发布到正式版,针对NPM 7做文档说明,得用--legacy-peer参数

  • 修改deploy脚本,去掉next标签
  • 文档中相关安装说明内容进行调整
  • 完成在NPM 7、NPM 6下的测试

更新到less 4.x

现在antd已经支持less 4.x,趁着没发正式版,把less更新一下

完善当前功能的文档

因为命令行工具的文件是不需要展示组件和交互的,考虑找一个轻量级的工具来做,dumi有点太复杂了

期望能自动管理多个单页应用

自动寻找pages目录(目录名是自定义的)下的所有目录,每一个目录都是一个单页应用,然后把对应的入口自动加到entry中

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.