nowa
nowa copied to clipboard
nowa 2.0
Why
-
webpack@1
已被 废弃 - 深度定制构建配置时,操作复杂甚至需要修改源码
- 配置只有一套。普适性稍差
- 没有插件 api。插件化不好开展
Solution
-
webpack
升级到3.x
- 从 cli 底层将现有配置与实现分离
- 提供 config 的模板(默认配置,或者我们认为的 best practice),用户可以根据需求方便地复写、添加
- 提供标准化的插件 api,规范调用方式
Target
简化项目文件:(1.0已经做到了)
- 隐藏项目中的 webpack / eslint / babel 各种配置文件
- 隐藏项目中的 npm script
抽离构建配置:(2.0的重点)
- 高可定制化
- 各业务线、用户使用独立 config (npm 包/文件)
- 构建配置编写/修改方式需要简单高效
- 协助提供定制、优化的 config
插件化:
- nowa-eslint
- nowa-proxy
- nowa-cloud-builder
- etc.
Pending Discussions
- abc.json 上的 nowa 相关配置完全移除。使用插件方式生成abc.json 以支持云构建
- 全局安装 vs 项目本地安装
由于 npm 到 5 了都没有实现基于全局的模式。意味着使用1.0全局的方式还是不太靠谱的。 考虑尽可能的使用本地安装的方式。 全局安装包 nowa 提供 nowa 命令。在项目目录下执行时 检查并运行项目下的 nowa 组件
- 使用 ESNext + webpack 构建工作流
- 使用
d.ts
ts描述文件描述外露接口 - 使用 airbnb 的编码规范
- API 文档
- 用户交互
Cases in Vision
有模板新项目:
- tnpm i nowa-cli nowa-init -g
- cd new-uxcore-component
- nowa init uxcore-template
- tnpm i
- nowa xxx
无模板项目(完美情况):
- tnpm i nowa-dev nowa-config-default -save-dev
- nowa xxx
构建配置编写:
nowa-config-xxxx index.js
// __dirname === project folder
export const webpack = () => ({
entry: ['./src/index'],
// copy your webpack config here
});
export const eslint = async() => {
};
export const pluginName = {
// ...
};
构建配置修改(部分修改):
.nowa.js
import { build as oldBuild } from 'nowa-config-default';
import { smart } from 'webpack-merge';
// export * from 'nowa-config-default';
export const build = {
...oldBuild,
webpack: smart(oldBuild.webpack, { devtool: false }),
};
nowa-config-xxxx 里的一些常用配置,entry、output 等,最好还是能通过命令行参数加进去
命令行的优先级 > .nowa.js 既然直接暴露了 export const build = merge(defaultWebpackConf, selfBuildCong), 那么原先的abc.json 里面的 buildvars / open / pages / mockapi / ... 放在哪里暴露?
nowa-config-xxxx index.js
export const server = {
webpack: {
// copy your webpack config here
},
src: 'src',
port: '3000',
open: true,
vars: {},
...
};
export const build = {
webpack: {
// copy your webpack config here
},
exportcss: true,
analyse: true,
dist: 'build',
groupVars: {},
...
};
export const eslint = {
};
export const UIPluginConfig = {
// ...
};
.nowa.js
import * as nowa from 'nowa-config-default';
import { smart } from 'webpack-merge';
const config = {...nowa};
config.build = {
webpack: smart(nowa.webpack, { devtool: false }),
};
config.server = {
...nowa.server,
open: false
}
export config;
@Jirapo 大部分的 abc.json 配置其实是个 alias。最终对应的是修改某个webpack 的配置。这种情况应该让用户自行修改。其目的是不引入多余的概念。 小部分的webpack 不相关的配置,会放到对应的插件配置里面去。
nowa-config-default
export const build = () = {};
export const server = () = {};
export const eslint = {};
export const proxy = {};
export const UIPlugin = {};
export const babelrc = {};
export const mockapi = {};
export const abc = {};
配置独立之后:
nowa-template:
- 考虑下 模板的继承和重用 (1.0有模板功能,但模板之间相互独立无法实现复用)
- 页面 / 组件 / 代码块 重用
支持环境
一般情况下
nowa
的开发和持续集成 基于 Current 的 node 版本
nowa
的运行环境为 当前 LTS 版本以上
nowa 2.0
-
node
6 及以上 -
npm
3 及以上
安装
概述
推荐在每个项目下单独安装
nowa
以及配置
全局安装
名字暂定
- nowa-cli
提供全局
nowa
命令、调用全局包、调用项目下的功能/插件
- nowa-global-init
提供全局
nowa init
命令、下载并初始化项目
项目安装包 (名字暂定)
- nowa
大包。包含所有可用插件
- nowa-core
只包含构建/开发核心
- nowa-template
- nowa-eslint
- nowa-prettier
配置
- nowa-config-default
- nowa-config-web-react
模版
- nowa-template-react
- nowa-template-uxcore
内部包
- nowa-core-util
- nowa-core-config-resolver
- ...
从带nowa配置的项目开始
使用
初始化项目
从项目模板初始化
使用此功能需要在全局安装
nowa-cli
nowa-global-init
包
nowa init
命令提供了以下几个常见模板
- react
- uxcore
- uxcore-component
- ....
要从模板初始化一个项目,请执行nowa init [templateName]
- 选择版本 / 分支
- 回答一些参数 ()
- 下载模板
- 回答模板定义问题
- 执行模板 hook
- npm i
同时也支持 nowa init [templateURL]
手动初始化(有 config)
我们提供了多套默认设置以覆盖多数开发者的要求
- 在此页面 选择配置
- 在项目下安装
nowa-core
nowa-config-default
npm i -D nowa-core nowa-config-default
现在可以在项目中使用配置可用中的 nowa命令
了
手动初始化 (无 config)
如果默认配置无法满足您的需求,或者是项目本身已经有自己的 webpack 配置。也可可以使用 nowa 进行构建
创建/移动你的
webpack
配置到nowa(.config).js
中
// TODO 示例图片
随后即可开始使用 nowa命令
开发
本地服务器开发
使用
可以通过 nowa server
命令来开启一个本地开发调试服务器。
请在项目根目录下执行。
nowa server
webpack 的构建输出文件将不会写到文件系统,而是缓存在内存中,在访问时直接输出。这样做可显著提高构建效率。
参数
// TODO 从 webpack-dev-server 选取参数
构建
可以通过 nowa build
命令进行构建。
请在项目根目录下执行。
nowa build --config default --dist .package
// TODO 从 webpack 选取参数
可配置多套构建方式,并通过第二参数进行调用
nowa build local
nowa build daily
nowa build prod
nowa build prod --output-path .package // 云构建
渐进配置
从已有配置开始
- 查看已有配置,并在
nowa.js
中对其部分作出覆盖或者修改 - 当配置过大 需要拆分时,可以使用
nowa
目录放置配置文件。使用index.js
导出配置 - 当配置改动量大或者需要共享时,发布到
npm
- 在新的项目
npm i
配置文件包 - 新项目的命令和构建行为与之前的项目相同
从空白项目开始
- 参考
手动初始化
章节 将webpack配置放置到合适位置 - 根据需求,完善配置、完善插件调用
- 当配置过大 需要拆分时,可以使用
nowa
目录放置配置文件。使用index.js
导出配置 - 当需要共享配置时,整理nowa 依赖,编写配置文件包并发布到
npm
// TODO 不通过 npm 如何共享配置?) - 在新的项目
npm i
配置文件包 - 新项目的命令和构建行为与之前的项目相同
插件
模板 nowa-template
- 模板支持 可通过模板生成各种文件。包括页面、组件、云构建文件、配置文件等等
ESlint nowa-eslint
- 格式化代码
Prettier nowa-prettier
- 格式化代码
Mock nowa-mock-server
- 启动 mock server
功能列表、状态
- 初始化、模板(思考中)
- 本地开发(webpack-dev-server)
- 模块热替换(webpack-dev-server 和 config 共同完成)
- 图片和svg(config中的 loader)
- 远程调试、路由(webpack-dev-server)
- 模拟数据(nowa-mock-server)
- 环境变量 (definePlugin) (nowa-webpack插件形式提供)
- 国际化(??)
- 云构建(模板?)
TODO
- 敲定配置文件格式
- 实现命令的 alias,
- 实现层级很深的常用配置。需要 alias 到根部 entry
- 插件 API
- init / template 构建 API,
创建doc repo 放文档吧
- 建议 nowa-global-init 依赖到 nowa-cli 里面去,全局只装一个;
- nowa init 的时候,(通过命令行交互方式)提示用户并自动安装 server/build 相关功能模块和所需配置依赖(远程拉一份配置列表让用户选择?);
- 如果(一个非 nowa 脚手架)项目中还没安装 nowa 相关依赖,那么在目录下执行 nowa server/build 时,同样执行
2.
的操作;
这样对小白用户来说只需要安装一个东西,其他都是通过配置来的~。~完美
nowa init 需要支持本地路径
@Jirapo
- 这边是随便写写的总结之后再整理好文档。
- 本地路径支持是需要加上,之前也有的
@gbk
-
nowa-global-(xxx)
模块 拆出去也是为了插件化。不过合并到一起出个整合大包也是 ok 的 -
nowa init 初始化相关功能模块。、这个应该是编写模板时在模板的这端做的。
- 选择版本 / 分支 (nowa-init 从模板拉取) (可以在这里给几个不同版本的模板,包含不同依赖和配置)
- 回答一些参数 (nowa-init 内置)
- 下载模板
- 回答模板定义问题
- 执行模板 hook (也可以在这里这里模板根据回答的问题来生成依赖, //TODO 定义模板的 API。。。)
- npm i
-
交互式这个逻辑可以有。但如果使用这个交互方式,这个的逻辑不太好放。。项目底下没有。全局的那个包只是提供个命令。加了判断逻辑就不够纯净了。。考虑下这种交互模式:
- 用户在空项目下执行 nowa [whateveryoulike] ,nowa-cli 报错说找不到项目底下的 nowa 功能包 (报错逻辑在 nowa-cli 肯定会有),并推荐在项目下安装 nowa 功能大包
- 用户安装 nowa 功能包, 并重新执行 nowa 命令
- nowa 功能包报错 说找不到可用的 config。给个链接贴到官方的 config 列表 让用户选择并安装
- 用户安装 config,问题解决
这样交互虽然会多 x 层。但每层的判断逻辑会分离的比较清楚。
参考webpackbin.com ,如这个简洁好用即可。
就一个要求,完全向下兼容即可
@wushanchao
这个类似于codepen
吧。。我觉得他这个配置方式比较有意思。可以根据需要勾选loader
这些。。其他的点没怎么看。。有遗漏的地方么?
这个 idea 收下了。可以考虑做 插件 / 引导页面帮助用户直接生成可用的配置。。
@lpgray
完全向下的兼容现在看上去是不太可能的。因为 webpack@1
到 @3
也是大版本升级。。不仅仅是配置和 自身API 的变化。同时也需要对 被打包的代码 进行变更。这块就完全没办法做到完全向下兼容了。。。
发布2.0从我角度上是需要 catch up 最新的打包/优化方式。这个不仅仅是需要从构建配置这块入手。比如 code splitting
和 tree shaking
这种优化是需要业务代码做调整的。
在产出2.0版本的同时在团队里面推配套的这种规范 / better practice
。最终希望能够给线上的项目带来落到实处的 benefits ,而不仅仅是为了拓展性和代码简洁性的重构。
由于这个的改动量不少。做出来的话也只能从新的项目开始应用。。 老项目的话,等2.0功能稳定下来了之后我们会帮忙提供升级技术支持。。
@tommytroylin 向下兼容可以考虑提供一个升级包,这块我来搞吧
alpha 版本
安装
全局安装
npm i nowa-cli@next -g
- nowa-cli
提供全局
nowa
命令、调用全局包、调用项目下的功能/插件
项目安装
npm i nowa-cli@next nowa-core@next nowa-build@next nowa-server@next -D
安装配置
react 项目
npm i nowa-config-react@next -D
使用
执行 nowa 以获取当前项目下可用的 nowa 组件列表
执行 nowa [命令] -h 来输出可用的所有配置
执行 nowa [命令] 来以默认配置(第一个配置包加上 ./nowa.js覆盖的部分)运行组件
执行 nowa [命令] [配置名] 来使用不同的配置 运行组件
配置编写及修改
配置包 demo
nowa-build alias 配置
nowa-server alias 配置
已知问题
- 运行 nowa 命令时会输出最终配置。此为测试使用
- 帮助信息现在的排列方式很奇怪
- nowa-cli 必须需要在本地安装才能读取到配置和组件。之后会考虑解决(重新分包)
- customFlag 这个option 暂不可用
TODO
- nowa.js (alias 配置中支持调用组件中的自定义方法。) 类似于:
build.addPlugin();
build.removePlugin();
build.addLoader();
build.replaceLoader();
build.removeLoader();
- 配置如何将自己需要的参数暴露给 cli (babel-loader/preset-env target)
- cli 运行时 hook
反馈
希望能够得到以下方面的意见。感谢
- 命令行方式,是否需要引入交互式命令?
- 配置的编写与修改是否方便
零配置启动一个 react 的 hello-world
- 下载nowa2-test.zip
- 解压
- 进入目录 执行
npm i
- 运行
npm run server
启动开发服务 - 运行
npm run build
进行打包
@gbk @Jirapo
本周我自己使用 nowa@2 起了一个react typescript项目,发现了一些易用性的问题。我个人也思考并实施了下解决方案。在此讨论一下。。
如果有其他的意见也请一并贴出,现在大改动还来得及。。。 敲定之后,下周开始完善面向用户交互/报错/提醒之后 就会发布 beta / release candidate 版本了。。。
- tsconfig.json 必须放置在 project 的根目录下。
下一步开发 init 组件。 可根据配置一键生成 .eslintrc abc.json 等等
- 现有的配置方式缺少可自定义性。比如希望修改 babel-preset-env 的 配置 十分困难
之前考虑过通过注入
__customFlag
参数来处理一些类似情况。但单个的参数完全无法满足需求。 解决方案:新增一个选项配置和全局方法以提供自定义性
// 之前输出配置方式如下
exports const build = {
context: __projroot, // nowa 挂载的全局数据
}; // 这里是 webpack config对象
新增之后
exports const buildOptions = { // 这个配置会传给 cli 用于输出帮助信息
skipMinify: {
default: false,
describe: 'skip minify js files',
type: 'boolean',
},
targetBrowsers: {
default: 'ie >= 9',
describe: 'https://babeljs.io/docs/plugins/preset-env/#optionstargets-browsers',
type: 'string',
},
};
exports const build = { // 之后此对象会递归过滤掉 undefined 值
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
options: {
presets: [
['env', { targets: { browsers: __option('targetBrowsers') }, modules: false }],
],
},
},
],
},
plugins: [
__option(({ skipMinify }) => skipMinify ? new MinifyPlugin() : undefined), // 全局方法名字暂定
],
};
而用户可以通过命令行参数和 alias进行配置
// nowa.js
export const nowa = {
build: {
__options: { // 配置名字暂定
targetBrowsers: 'chrome >= 50'
},
},
};
- 配置需要执行一些回调。用以调用组件上的修改配置的方法
暂定在配置中读取
- buildWillProcess 在 build 组件读取到所有 config 之后。处理(merge)config 之前
- buildWillRun 在 build 组件运行之前(处理最终传给webpack/第三方工具的配置)
- buildDidRun 在 build 组件执行完成之后调用
nowa 脚手架 / init 更改
-
废弃掉之前的 name 命名方式。文件名、文件内容 均 统一使用 handlebars
干掉 ejs 吧。。。语法太 XML 了。。
-
可配置多项任务,根据命令 生成 项目源文件/配置文件/等等
-
项目整体的模板沿用 template-xxxx,init项目时 直接下载并compile
-
项目内的配置放在 config 包内或者 项目的 nowa 目录下