build-scripts

授权协议 MIT License
开发语言 JavaScript
所属分类 Web应用开发、 常用JavaScript包
软件类型 开源软件
地区 不详
投 递 者 朱啸
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

1.x | 0.x

build-scripts

基于 Webpack 的插件化工程构建工具,支持快速建设一套开箱即用的工程方案。

目录

特性

  • 完善灵活的插件能力,帮助扩展不同工程构建的场景
  • 提供多构建任务机制,支持同时构建多份产物
  • 基于 webpack-chain 提供灵活的自定义 webpack 配置能力
  • 标准化构建&调试的完整流程,同时提供 Hook 能力进行定制
  • 已支持多种场景:
    • React 项目开发
    • Rax 项目开发
    • NPM 包开发
    • 天马模块开发

常见问题

NPM 包名是 build-scripts 还是 @alib/build-scripts

1.x 以及未来都以 build-scripts 为准,0.x 版本当时因为命名被占用只能使用 @alib/build-scripts 这个包名。

1.x 相比 0.x 有什么变化?

参考 版本升级 章节。

何时使用 build-scripts?

多个项目共享 Webpack 以及其他工程能力,同时支持插件扩展&修改配置。

使用场景

基于 build-scripts 目前已支持多种场景,覆盖大多数的研发场景,当然你可以完全自定义一套工程能力。

React 项目开发

Rax 项目开发

天马模块

仅阿里内部

NPM 包开发

自定义工程

如果不想使用上述官方提供的解决方案,也可以基于 build-scripts 自定义完整的工程能力,具体请参考 example

能力介绍

命令行能力

build-scripts 核心支持了 start、build 和 test 三个命令。

启动调试

$ build-scripts start --help

Usage: build-scripts start [options]

Options:
  --port <port>      服务端口号
  --host <host>      服务主机名
  --config <config>      自定义配置文件路径(支持 json 或者 js,推荐命名 build.config.js/build.json)

执行构建

$ build-scripts build --help

Usage: build-scripts build [options]

Options:
  --config <config>      同 start

运行单测

$ build-scripts test --help

Usage: build-scripts test [options]

Options:
  --config <config>      同 start

配置文件

build-scripts 默认将 build.json 作为工程配置文件,运行 build-scripts 命令时会默认读取当前目录的 build.json 文件。

配置方式:

{
  "externals": {
    "react": "React"
  },
  "plugins": [
    "build-plugin-component",
    "./build.plugin.js"
  ]
}

build.json 中核心包括两部分内容:

  • 基础配置:比如示例的 externals 字段,默认情况下不支持任何字段,由基础插件通过 registerUserConfig API 注册扩展
  • 插件配置:二三方插件,以及针对单个项目通过本地插件实现 webpack config 的更改

除了 json 类型以外,build-scripts 也支持 js 类型的配置文件:

// build.plugin.js
module.exports = {
  plugins: []
}

然后通过 --config 参数指定即可 build-scripts start --config build.config.js

配置插件

通过 build.json 中提供的 plugins 字段可配置插件列表,插件数组项每一项代表一个插件,build-scripts 将按顺序执行插件列表,插件配置形式如下:

{
  "plugins": [
    // 数组第一项为插件名,第二项为插件参数
    ["build-plugin-fusion", {
      "themePackage": "@icedesign/theme"
    }]
  ]
}

本地自定义配置

如果基础配置和已有插件都无法支持业务需求,可以通过本地插件自定义配置来实现,新建 build.plugin.js 文件作为一个自定义插件,然后写入以下代码:

module.exports = ({ context, onGetWebpackConfig }) => {
  // 这里面可以写哪些,具体请查看插件开发章节
  onGetWebpackConfig((config) => {
  });
}

最后在 build.json 里引入自定义插件即可:

{
  "plugins": [
    "build-plugin-component",
    "./build.plugin.js"
  ]
}

插件开发

通过命令创建一个插件 npm 包:

$ npm init npm-template <pluginName> build-plugin-template
$ cd <pluginName>

插件本质上是一个 Node.js 模块,入口如下:

module.exports = ({ context, onGetWebpackConfig, log, onHook, ...rest }, options) => {
  // 第一项参数为插件 API 提供的能力
  // options:插件自定义参数
};

插件方法会收到两个参数,第一个参数是插件提供的 API 接口和能力,推荐解构方式按需使用 API,第二个参数 options 是插件自定义的参数,由插件开发者决定提供哪些选项给用户自定义。

插件 API

插件可以方便扩展和自定义工程能力,这一切都基于 build-scripts 提供的插件 API。

context

context 参数包含运行时的各种环境信息:

  • command 当前运行命令 start|build|test
  • commandArgs script 命令执行时接受到的参数
  • rootDir 项目根目录
  • originalUserConfig 用户在 build.json 中配置的原始内容
  • userConfig 用户配置,包含被 modifyUserConfig 修改后的结果
  • pkg 项目 package.json 的内容
  • webpack webpack 实例,插件中针对 webpack 的逻辑均使用此方式引入
module.exports = ({ context }) => {
  const { userConfig, command, webpack } = context;
  console.log('userConfig', userConfig);
  console.log('command', command);
};

onGetWebpackConfig

通过 onGetWebpackConfig 获取 webpack-chain 形式的配置,并对配置进行自定义修改:

// 场景一:修改所有 webpack 配置
module.exports = ({ onGetWebpackConfig }) => {
  onGetWebpackConfig((config) => {
    config.entry('src/index');
  });
}

// 场景二:多 webpack 任务情况下,修改指定任务配置
module.exports = ({onGetWebpackConfig, registerTask}) => {
  registerTask('web', webpackConfigWeb);
  registerTask('weex', webpackConfigWeex);

  onGetWebpackConfig('web'(config) => {
    config.entry('src/index');
  });

  onGetWebpackConfig('weex'(config) => {
    config.entry('src/app');
  });
}

onHook

通过 onHook 监听命令运行时事件,onHook 注册的函数执行完成后才会执行后续操作,可以用于在命令运行中途插入插件想做的操作:

module.exports = ({ onHook }) => {
  onHook('before.start.load', () => {
    // do something before dev
  });
  onHook('after.build.compile', stats => {
    // do something after build
  });
};

目前的命令执行生命周期如下:

start 命令:

生命周期 参数 调用时机
before.start.load { args: CommandArgs; webpackConfig: WebpackConfig[] } 获取 webpack 配置之前
before.start.run { args: CommandArgs; webpackConfig: WebpackConfig[] } webpack 执行构建之前
after.start.compile { url: string; stats: WebpackAssets; isFirstCompile: boolean } 编译结束,每次重新编译都会执行
before.start.devServer { url: string; devServer: WebpackDevServer } server 中间件加载后,webpack devServer 启动前
after.start.devServer { url: string; devServer: WebpackDevServer } webpack devServer 启动后

build 命令:

生命周期 参数 调用时机
before.build.load { args: CommandArgs; webpackConfig: WebpackConfig[] } 获取 webpack 配置之前
before.build.run { args: CommandArgs; webpackConfig: WebpackConfig[] } webpack 执行构建之前
after.build.compile { url: string; stats: WebpackAssets; isFirstCompile } 编译结束

test 命令:

生命周期 参数 调用时机
before.test.load { args: CommandArgs; webpackConfig: WebpackConfig[] } 获取 jest 配置之前
before.test.run { args: CommandArgs; config: JestConfig } jest 执行构建之前
after.test { result: JestResult } 测试结束

log

build-scripts 统一的 log 工具,底层使用 npmlog ,便于生成统一格式的 log:

module.exports = ({ log }) => {
  log.verbose('verbose');
  log.info('info');
  log.error('error');
  log.warn('warn');
};

registerUserConfig

通过 registerUserConfig 注册 build.json 中的顶层配置字段,注册是可以进行用户字段校验,支持传入单个配置对象或者包含多个配置对象的数组。

方法生效的生命周期,在 registerTask 和 onGetWebpackConfig 之间。

配置对象字段如下:

  • name (string)

字段名称,唯一标识,多个插件无法注册相同的字段保留字段:plugins

  • validation(string|function)

字段校验,支持 string 快速校验,string|boolean|number,也可以自定义函数,根据 return 值判断校验结果

  • ignoreTasks(string[])

配置忽略指定 webpack 任务

  • configWebpack(function)

字段效果,具体作用到 webpack 配置上,接收参数:

  • config:webpack-chain 形式的配置
  • value: build.json 中的字段值
  • context:与外部 context 相同,新增字段 taskName 表现当前正在修改的 task
module.exports = ({ registerUserConfig }) => {
  registerUserConfig({
    name: 'entry',
    // validation: 'string',
    validation: value => {
      return typeof value === 'string';
    },
    configWebpack: (config, value, context) => {
      config.mode(value);
    },
  });
};

registerTask

用于注册多 webpack 任务,比如 build-plugin-react-app 上已完整支持 React 链路开发,大部分情况下在默认 webpack 任务上拓展即可,无需额外注册.

// 注册的 config 必须是以 webpack-chain 形式组织
module.exports = ({ registerTask }) => {
  registerTask('web', webpackConfigWeb);
  registerTask('component', webpackConfigComponent);
};

cancelTask

用于取消已注册任务

module.exports = ({ cancelTask }) => {
  cancelTask('web');
};

hasRegistration

判断 build.json 中的顶层配置字段或者 cli 参数是否已经注册:

module.exports = ({ hasRegistration }) => {
  // 判断 build.json 顶层配置字段 entry 是否已配置
  const hasEntryRegistered = hasRegistration('entry');

  // 判断 cli --https 参数是否已被注册
  const hasHttpsRegistered = hasRegistration('https' 'cliOption');
  ...
}

modifyConfigRegistration

用于修改已注册用户配置的行为:

module.exports = ({ modifyConfigRegistration }) => {
  modifyConfigRegistration('name', configRegistration => {
    return {
      ...configRegistration,
      // 修正验证字段
      validation: 'string',
    };
  });
};

modifyUserConfig

通过 modifyUserConfig 可以修改通过 registerUserConfig 注册的基础配置,在插件中快速复用基础配置的处理逻辑:

module.exports = ({ modifyUserConfig }) => {
  modifyUserConfig(originConfig => {
    // 通过函数返回批量修改
    return { ...originConfig, define: { target: 'xxxx' } };
  });
};

通过指定具体修改的基础配置,快速完成配置的修改:

module.exports = ({ modifyUserConfig }) => {
  modifyUserConfig('entry', 'src/app');

  // 通过对象路径修改,比如修改对象 { outputAssetsPath: { js: 'js-dist'} } 可通过以下方式
  modifyUserConfig('outputAssetsPath.js', 'js');

  // 支持深合并,默认情况下 modifyUserConfig 将覆盖原有配置,通过配置参数支持配置的合并
  modifyUserConfig('outputAssetsPath', {
    js: 'js-output'
  }, { deepmerge: true });
};

API 执行的生命周期:所有插件对于修改配置函数将保存至 modifyConfigRegistration 中,在 runUserConfig 执行前完成对当前 userConfig 内容的修改

registerCliOption

注册各命令上支持的 cli 参数,比如 npm start --https 来开启 https:

module.exports = ({ registerCliOption }) => {
  registerCliOption({
    name: 'https', // 注册的 cli 参数名称,
    commands: ['start'], // 支持的命令,如果为空默认任何命令都将执行注册方法
    configWebpack: (config, value, context) => {
      // 对应命令链路上的需要执行的相关操作
    },
  });
};

注册函数执行周期,在 userConfig 相关注册函数执行之后。

modifyCliRegistration

用于修改已注册 cli 配置的行为:

module.exports = ({ modifyConfigRegistration }) => {
  modifyCliRegistration('https', cliRegistration => {
    return {
      ...cliRegistration,
      // 修正 commands 字段
      commands: ['start'],
    };
  });
};

getAllTask

用于获取所有注入任务的名称:

module.exports = ({ getAllTask }) => {
  const taskNames = getAllTask();
  // ['web', 'miniapp']
};

插件间通信

在一些业务场景下,插件间需要进行通信:

  1. 不同插件之间需要知道彼此的存在来确定是否执行相应的逻辑
  2. 多个插件共有的配置信息可以抽出来,在某个插件中进行配置
  3. 上层插件的执行,需要依赖基础插件提供的方法

基于上述的诉求,API 层面提供 setValuegetValue 来用于数据的存取,registerMethodapplyMethod 来解决方法的复用。

setValue

用来在 context 中注册变量,以供插件之间的通信。

module.exports = ({ setValue }) => {
  setValue('key', 123);
};

getValue

用来获取 context 中注册的变量。

module.exports = ({ getValue }) => {
  const value = getValue('key'); // 123
};

registerMethod

向工程核心注册相关方法,方便其他插件进行复用:

module.exports = ({ registerMethod }) => {
  // 注册方法
  registerMethod('pipeAppRouterBefore', content => {
    // 执行相关注册逻辑,可以返回相应的值
    return true;
  });
};

registerMethod 注册方式时,通过参数指定可以获取调用该方法的具体插件名:

module.exports = ({ registerMethod }) => {
  // 注册方法
  registerMethod('pipeAppRouterBefore', (pluginName) => (content) => {
    console.log('plugin name', pluginName);
    console.log('content', content);
    // 执行相关注册逻辑,可以返回相应的值
    return true;
  }, { pluginName: true });
};

applyMethod

调用其他插件的注册方法

module.exports = ({ applyMethod }) => {
  // 使用其他差价注册方法的方式,如果插件未注册,将返回一个 error 类型的错误
  // 类似 new Error(`apply unkown method ${name}`)
  const result = applyMethod('pipeAppRouterBefore', 'content');
};

版本升级

0.x -> 1.x

1.x 核心变化:

  • 包名由 @alib/build-scripts 切换为 build-scripts
  • 不再依赖 webpack&jest&webpack-dev-server,建议由基础插件或项目自身依赖
  • 插件上下文 context 增加 originalUserConfig 字段,用于读取用户原始配置
  • userConfig 类型校验增强,支持 string | object | array 校验

除了前两点属于不兼容改动,其他能力都保持向前兼容。

自定义工程

在 package.json 中增加依赖:

{
  "devDependencies": {
+    "jest": "^26.4.2",
+    "webpack": "^4.27.1",
+    "webpack-dev-server": "^4.0.0",
-    "@alib/build-scripts": "^0.1.0",
+    "build-scripts": "^1.0.0",
  }
}

其中 jest 可按需判断是否需要安装,webpack 版本按需选择。修改完成后重装依赖然后重启即可。

React 项目(icejs)

升级 icejs 2.0. 即可。

Rax 项目(rax-app)

待支持

业务组件(build-plugin-component)

在 package.json 中升级依赖:

{
  "devDependencies": {
-    "@alib/build-scripts": "^0.1.0",
+    "build-scripts": "^1.0.0",
-    "build-plugin-component": "^1.0.0",
+    "build-plugin-component": "^1.6.5",
  }
}

build-plugin-component 从 1.6.5 开始同时兼容 build-scripts 0.x 和 1.x 两个版本

天马模块(@ali/build-plugin-pegasus-base)

待支持

License

MIT

  • https://www.jianshu.com/p/630206347112 简介 build.gradle是gradle中非常重要的一个文件,因为它描述了gradle中可以运行的任务,今天本文将会带大家体验一下如何创建一个build.gradle文件和如何编写其中的内容。 project和task gradle是一个构建工具,所谓构建工具就是通过既定的各种规则,将原代码或者原文件通过一定的tas

  • ‘react-scripts’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 报这种错误的时候可以重新装 yarn add react-scripts 然后重启项目就可以了,赶快试试吧!!! yarn start [巴拉巴拉]

  • create-react-app创建的React项目时,有时在安装完其他组件后,再次运行 npm start 命令时会报以上错误,让我很郁闷,不过在上网搜了这个错后原来: 是create-react-app有丢包的缺陷,手动安装包后,需要重新npm install一下,这样node_modules/.bin/目录下才会重新出现react-scripts的文件,这样npm start命令才能正常执行

  • 如果npm install报错,单独安装这个包,加上参数:–ignore-scripts npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! deasync@0.1.21 install: `node ./build.js` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the deasync

  • 关于GENERATE_SOURCEMAP的作用原理在这篇文章中介绍过。 create-react-app :不产生source-map来缩减打包文件体积 可以通过创建.env环境变量文件影响react-scripts start/build等命令。其实还有另一种更灵活的方式设置环境变量,使用export可以对不同的命令设置不同的环境变量. 打开package.json,找到scripts配置项

  • 简介 build.gradle是gradle中非常重要的一个文件,因为它描述了gradle中可以运行的任务,今天本文将会带大家体验一下如何创建一个build.gradle文件和如何编写其中的内容。 project和task gradle是一个构建工具,所谓构建工具就是通过既定的各种规则,将原代码或者原文件通过一定的task处理过后,打包生成目标文件的步骤。 所以我们在gradle中有两个非常重要的

  • 官网用法 用法:vue-cli-service build [options] [entry|pattern] 选项: --mode 指定环境模式 (默认值:production) --dest 指定输出目录 (默认值:dist) --modern 面向现代浏览器带自动回退地构建应用 --target app | lib | wc

 相关资料
  • import "go/build" Package build gathers information about Go packages. Go Path &para The Go path is a list of directory trees containing Go source code. It is consulted to resolve imports that cannot

  • Netlify Build runs the build command and Build Plugins and bundles Netlify Functions. Build Plugins extend the functionality of the Netlify Build process. You can install plugins made by others or wri

  • 构建命令,用于渲染您的 md,并输出静态 html: mdbook build 它会尝试解析你的SUMMARY.md文件,以了解您的图书的结构并获取相应的文件. 为方便起见,渲染的输出将保持与源目录结构相同。因此,大型书籍在渲染时能保持结构化. build命令可以将目录作为参数,用作本书的根目录,而不是当前工作目录. mdbook build path/to/book 当你使用--open(-

  • NPM tasks Running your first build The build process is using Webpack, Babel and as well as npm tasks listed in package.json. During this process, the source located in the src/* directory are transfo

  • build 用法 Usage: docker build [OPTIONS] PATH | URL | - Build a new image from the source code at PATH -f, --file="" Name of the Dockerfile (Default is 'PATH/Dockerfile') --force-rm=false

  • go build命令用于编译我们指定的源码文件或代码包以及它们的依赖包。 例如,如果我们在执行go build命令时不后跟任何代码包,那么命令将试图编译当前目录所对应的代码包。例如,我们想编译goc2p项目的代码包logging。其中一个方法是进入logging目录并直接执行该命令: hc@ubt:~/golang/goc2p/src/logging$ go build 因为在代码包logging