mirror of
https://gitee.com/WeBank/fes.js.git
synced 2024-11-30 02:37:52 +08:00
feat: create-fes-app支持创建插件项目
This commit is contained in:
commit
9f349343b9
@ -82,6 +82,19 @@ const config: UserConfig<DefaultThemeOptions> = {
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
'@vuepress/docsearch',
|
||||
{
|
||||
appId: '4ZF3BCJTP5',
|
||||
apiKey: '09ff75bbe16bc6e166e103ffb57e10ea',
|
||||
indexName: 'fesjs',
|
||||
locales: {
|
||||
'/': {
|
||||
placeholder: '搜索文档',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,11 @@
|
||||
# 贡献指南
|
||||
|
||||
## 概览
|
||||
## 包概览
|
||||
|
||||
项目仓库借助于 [Yarn Classic 工作区](https://classic.yarnpkg.com/zh-Hans/docs/workspaces) 来实现 [Monorepo](https://en.wikipedia.org/wiki/Monorepo) ,在 `packages` 目录下存放了多个互相关联的独立 Package 。
|
||||
项目仓库借助于 [Yarn 工作区](https://classic.yarnpkg.com/zh-Hans/docs/workspaces) 来实现 [ Monorepo](https://en.wikipedia.org/wiki/Monorepo) ,在 `packages` 目录下存放多个互相关联的独立包。
|
||||
|
||||
- `@fesjs/create-fes-app`: 创建项目模板模块。提供`create-fes-app`命令,提供创建多种类型项目模板的能力。
|
||||
|
||||
- `@fesjs/fes`: 入口模块。提供`fes`命令和 API 入口。
|
||||
|
||||
- `@fesjs/compiler`: 编译时插件管理模块。定义插件的生命周期、插件配置、插件通讯机制等。
|
||||
|
||||
- `@fesjs/runtime`: 运行时插件模块。集成了vue-router,定义运行时插件生命周期、插件通讯机制。
|
||||
@ -20,51 +18,95 @@
|
||||
|
||||
- `@fesjs/plugin-${name}`: 官方插件。
|
||||
|
||||
- `@fesjs/fes`: 是 `@fesjs/compiler` + `@fesjs/runtime` + `@fesjs/preset-build-in` 的封装。用户只需要安装此依赖和额外的插件或者插件集。
|
||||
- `@fesjs/fes`: 入口模块。提供`fes`命令和 API 入口,封装`@fesjs/compiler` + `@fesjs/runtime` + `@fesjs/preset-build-in`,用户只需要安装此依赖和其他插件。
|
||||
|
||||
## 开发配置
|
||||
|
||||
## 开发准备
|
||||
|
||||
开发要求:
|
||||
|
||||
- [Node.js](http://nodejs.org) **version 12+**
|
||||
- [Yarn v1 classic](https://classic.yarnpkg.com/zh-Hans/docs/install)
|
||||
|
||||
克隆代码仓库,并安装依赖:
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
监听源文件修改:
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
打开另一个终端,开始开发项目文档网站:
|
||||
|
||||
```bash
|
||||
yarn docs:dev
|
||||
```
|
||||
- [Node.js v14+](http://nodejs.org)
|
||||
- [Yarn v1](https://classic.yarnpkg.com/zh-Hans/docs/install)
|
||||
|
||||
本项目开发使用的一些主要工具:
|
||||
|
||||
- [Jest](https://jestjs.io/) 用于单元测试
|
||||
- [ESLint](https://eslint.org/) + [Prettier](https://prettier.io/) 用于代码检查和格式化
|
||||
- [@umi/father](https://github.com/umijs/father) 用于将ES6语法编译成ES5或者CommonJS
|
||||
|
||||
## 开发脚本
|
||||
克隆仓库:
|
||||
|
||||
### `yarn build`
|
||||
```bash
|
||||
git clone https://github.com/WeBankFinTech/fes.js.git
|
||||
```
|
||||
|
||||
`build` 命令会使用 `father-build` 将 ES6 编译为 CommonJS。
|
||||
进入`fes.js`目录,安装依赖:
|
||||
|
||||
本项目在编写Node端的代码时也用ES6,所以你在克隆代码仓库后,可能需要先执行该命令来确保项目代码可以顺利运行,因为编译后的 JS 文件被 `.gitignore` 排除在仓库以外了。
|
||||
### `yarn docs:dev`
|
||||
`docs:` 前缀表明,这些命令是针对文档 (documentation) 进行操作的,即 `docs` 目录。
|
||||
使用 Vue Press在本地启动文档网站服务器,用于实时查看文档效果。
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
|
||||
### 调试功能
|
||||
在开发完插件代码后,需要在template项目中验证功能
|
||||
- 进入`packages/template`目录
|
||||
- 执行`yarn dev`
|
||||
## 贡献文档
|
||||
文档代码在`docs`目录,基于 [vuepress](https://v2.vuepress.vuejs.org/zh/) 实现。
|
||||
|
||||
#### 第一步:启动服务
|
||||
|
||||
```bash
|
||||
yarn docs:dev
|
||||
```
|
||||
|
||||
#### 第二步:修改md文件
|
||||
菜单配置在`/docs/.vuepress/configs/sidebar/zh.ts`中,可以通过此配置找到对应想修改的文档。
|
||||
|
||||
如果想添加图片,则可以先把图片添加至`/docs/.vuepress/public`,在代码中使用:
|
||||
```html
|
||||
<img :src="$withBase('framework.png')" alt="架构">
|
||||
```
|
||||
|
||||
#### 第三步:查看更新
|
||||
当md文档保存后,文档会自动更新,在`http://localhost:8080/`查看。
|
||||
|
||||
|
||||
|
||||
## 贡献源码
|
||||
`Fes.js`统一使用`ES Module`规范编写源码,代码会在 node 端和浏览器端执行,所以源码需要编译后才能发布成包,再被执行。
|
||||
|
||||
#### 启动编译服务
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
当我们修改`build.config.js`中配置的包代码时,会把`src`目录的源码编译后到`lib`目录。
|
||||
|
||||
#### 修改源码
|
||||
在了解`Fes.js`设计前提下,修改核心代码或者插件代码。
|
||||
|
||||
#### 验证修改内容
|
||||
|
||||
根据需求选择模板项目来验证修改内容,比如选择`fes-template`:
|
||||
1. 查看需待验证包是否已经添加到模板项目的依赖中,如果没有则在模板项目的 package.json 中添加包依赖,添加后在根目录执行`yarn`关联依赖
|
||||
2. 启动模板项目的开发服务
|
||||
```bash
|
||||
cd packages/fes-template
|
||||
yarn dev
|
||||
```
|
||||
3. 在项目模板中添加代码验证修改内容
|
||||
4. 打开`localhost:8000`查看结果
|
||||
|
||||
#### 快速调试技巧
|
||||
每次修改插件或者核心代码后,等待自动编译完,需要在模板目录重新执行`fes dev`,比较费时费力。
|
||||
|
||||
可以先在模板的 `.fes` 目录中找到对应临时代码,更改逻辑,验证完后再将变更逻辑保存到正式文件中。
|
||||
|
||||
:::warning
|
||||
直接修改临时文件切莫重新执行`fes dev`,修改会被覆盖。
|
||||
:::
|
||||
|
||||
|
||||
## 提交PR
|
||||
|
||||
1. fork项目!
|
||||
2. 创建你的功能分支: git checkout -b my-new-feature
|
||||
3. 本地提交新代码: git commit -am 'Add some feature'
|
||||
4. 推送本地到服务器分支: git push origin my-new-feature
|
||||
5. 创建一个PR
|
@ -36,6 +36,33 @@ API 对象是构建流程管理 Service 类的实例,api 提供一些有用的
|
||||
- **enableBy**, 是否开启插件,可配置某些场景下禁用插件。
|
||||
|
||||
|
||||
## 创建插件
|
||||
|
||||
##### 第一步:安装`create-fes-app`
|
||||
```bash
|
||||
npm i -g @fesjs/create-fes-app
|
||||
```
|
||||
|
||||
|
||||
##### 第二步:创建插件项目
|
||||
|
||||
```bash
|
||||
create-fes-app pluginName
|
||||
```
|
||||
在询问`Pick an template`时选择`Plugin`!
|
||||
|
||||
##### 第三步:进入插件目录 & 安装依赖
|
||||
```bash
|
||||
cd pluginName & yarn
|
||||
```
|
||||
|
||||
##### 第四步:启动编译
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
##### 第五步:使用插件API完成你的插件!(可以参考其他插件理解api用法和场景)
|
||||
|
||||
## 发布到 npm
|
||||
|
||||
以 `@fesjs/preset-`、`@fesjs/plugin-`、`@webank/fes-preset-`、`@webank/fes-plugin-`、`fes-preset-` 和 `fes-plugin-` 开头的依赖会被 Fes.js 自动注册为插件或插件集。
|
||||
|
24
packages/create-fes-app/src/generator/Plugin.js
Normal file
24
packages/create-fes-app/src/generator/Plugin.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { Generator } from '@fesjs/utils';
|
||||
|
||||
export default class AppGenerator extends Generator {
|
||||
constructor({ cwd, args, path, targetDir, name }) {
|
||||
super({
|
||||
cwd,
|
||||
args,
|
||||
});
|
||||
this.path = path;
|
||||
this.targetDir = targetDir;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
async writing() {
|
||||
this.copyDirectory({
|
||||
context: {
|
||||
version: require('../../package.json').version,
|
||||
name: this.name,
|
||||
},
|
||||
path: this.path,
|
||||
target: this.targetDir,
|
||||
});
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import inquirer from 'inquirer';
|
||||
|
||||
import { clearConsole } from './utils';
|
||||
import AppGenerator from './generator/App';
|
||||
import PluginGenerator from './generator/Plugin';
|
||||
|
||||
export default async ({ cwd, args }) => {
|
||||
if (args.proxy) {
|
||||
@ -19,12 +20,14 @@ export default async ({ cwd, args }) => {
|
||||
const result = validateProjectName(name);
|
||||
if (!result.validForNewPackages) {
|
||||
console.error(chalk.red(`Invalid project name: "${name}"`));
|
||||
result.errors && result.errors.forEach((err) => {
|
||||
console.error(chalk.red.dim(`Error: ${err}`));
|
||||
});
|
||||
result.warnings && result.warnings.forEach((warn) => {
|
||||
console.error(chalk.red.dim(`Warning: ${warn}`));
|
||||
});
|
||||
result.errors &&
|
||||
result.errors.forEach((err) => {
|
||||
console.error(chalk.red.dim(`Error: ${err}`));
|
||||
});
|
||||
result.warnings &&
|
||||
result.warnings.forEach((warn) => {
|
||||
console.error(chalk.red.dim(`Warning: ${warn}`));
|
||||
});
|
||||
throw new Error('Process exited');
|
||||
}
|
||||
if (fs.pathExistsSync(targetDir) && !args.merge) {
|
||||
@ -36,8 +39,8 @@ export default async ({ cwd, args }) => {
|
||||
{
|
||||
name: 'ok',
|
||||
type: 'confirm',
|
||||
message: 'Generate project in current directory?'
|
||||
}
|
||||
message: 'Generate project in current directory?',
|
||||
},
|
||||
]);
|
||||
if (!ok) {
|
||||
return null;
|
||||
@ -52,9 +55,9 @@ export default async ({ cwd, args }) => {
|
||||
choices: [
|
||||
{ name: 'Overwrite', value: 'overwrite' },
|
||||
{ name: 'Merge', value: 'merge' },
|
||||
{ name: 'Cancel', value: false }
|
||||
]
|
||||
}
|
||||
{ name: 'Cancel', value: false },
|
||||
],
|
||||
},
|
||||
]);
|
||||
if (!action) {
|
||||
return null;
|
||||
@ -75,17 +78,18 @@ export default async ({ cwd, args }) => {
|
||||
choices: [
|
||||
{ name: 'PC, suitable for management desk front-end applications', value: 'pc' },
|
||||
{ name: 'H5, suitable for mobile applications', value: 'h5' },
|
||||
{ name: 'Cancel', value: false }
|
||||
]
|
||||
}
|
||||
{ name: 'Plugin, suitable for fes plugin', value: 'plugin' },
|
||||
{ name: 'Cancel', value: false },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
if (template) {
|
||||
if (template === 'pc' || template === 'h5') {
|
||||
const generator = new AppGenerator({
|
||||
cwd,
|
||||
args,
|
||||
targetDir,
|
||||
path: path.join(__dirname, `../templates/app/${template}`)
|
||||
path: path.join(__dirname, `../templates/app/${template}`),
|
||||
});
|
||||
await generator.run();
|
||||
console.log();
|
||||
@ -94,5 +98,20 @@ export default async ({ cwd, args }) => {
|
||||
console.log('$ yarn');
|
||||
console.log('$ yarn dev');
|
||||
console.log();
|
||||
} else if (template === 'plugin') {
|
||||
const generator = new PluginGenerator({
|
||||
cwd,
|
||||
args,
|
||||
targetDir,
|
||||
path: path.join(__dirname, '../templates/plugin'),
|
||||
name,
|
||||
});
|
||||
await generator.run();
|
||||
console.log();
|
||||
console.log(chalk.green(`plugin ${projectName} created successfully, please execute the following command to use:`));
|
||||
console.log(`$ cd ${projectName}`);
|
||||
console.log('$ yarn');
|
||||
console.log('$ yarn dev');
|
||||
console.log();
|
||||
}
|
||||
};
|
||||
|
16
packages/create-fes-app/templates/plugin/.editorconfig
Normal file
16
packages/create-fes-app/templates/plugin/.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# http://editorconfig.org
|
||||
|
||||
root = true
|
||||
lib
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
21
packages/create-fes-app/templates/plugin/.eslintrc.js
Normal file
21
packages/create-fes-app/templates/plugin/.eslintrc.js
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports = {
|
||||
extends: ['@webank/eslint-config-webank/vue.js'],
|
||||
globals: {
|
||||
// 这里填入你的项目需要的全局变量
|
||||
// 这里值为 false 表示这个全局变量不允许被重新赋值,比如:
|
||||
//
|
||||
// Vue: false
|
||||
__DEV__: false,
|
||||
},
|
||||
rules: {
|
||||
'vue/comment-directive': 'off',
|
||||
'global-require': 'off',
|
||||
'import/no-unresolved': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
'no-undefined': 'off',
|
||||
'vue/valid-template-root': 'off',
|
||||
},
|
||||
env: {
|
||||
jest: true,
|
||||
},
|
||||
};
|
2
packages/create-fes-app/templates/plugin/.gitignore
vendored
Normal file
2
packages/create-fes-app/templates/plugin/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
lib
|
4
packages/create-fes-app/templates/plugin/.prettierrc
Normal file
4
packages/create-fes-app/templates/plugin/.prettierrc
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none"
|
||||
}
|
3
packages/create-fes-app/templates/plugin/build.config.js
Normal file
3
packages/create-fes-app/templates/plugin/build.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
copy: ['runtime'],
|
||||
};
|
49
packages/create-fes-app/templates/plugin/package.json.tpl
Normal file
49
packages/create-fes-app/templates/plugin/package.json.tpl
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "fes-plugin-{{{name}}}",
|
||||
"version": "3.0.0",
|
||||
"description": "一个fes.js插件",
|
||||
"main": "lib/index.js",
|
||||
"files": [
|
||||
"lib",
|
||||
"README.md",
|
||||
"types.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "node scripts/build.js --watch",
|
||||
"build": "node scripts/build.js",
|
||||
"lint": "eslint -c ./.eslintrc.js --ext .js,.jsx,.vue,.ts"
|
||||
},
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
],
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@webank/eslint-config-webank": "^1.2.3",
|
||||
"chalk": "^4.1.2",
|
||||
"chokidar": "^3.5.2",
|
||||
"deepmerge": "^4.2.2",
|
||||
"fs-extra": "^10.0.0",
|
||||
"husky": "^4.3.0",
|
||||
"lint-staged": "^10.4.0",
|
||||
"yargs-parser": "^20.2.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@fesjs/fes": "^3.0.0-beta.0",
|
||||
"vue": "^3.0.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,vue,ts}": [
|
||||
"eslint --format=codeframe"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
||||
}
|
||||
},
|
||||
"typings": "./types.d.ts"
|
||||
}
|
144
packages/create-fes-app/templates/plugin/scripts/build.js
Normal file
144
packages/create-fes-app/templates/plugin/scripts/build.js
Normal file
@ -0,0 +1,144 @@
|
||||
// 关闭 import 规则
|
||||
/* eslint import/no-extraneous-dependencies: 0 */
|
||||
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
const path = require('path');
|
||||
const merge = require('deepmerge');
|
||||
const chokidar = require('chokidar');
|
||||
const chalk = require('chalk');
|
||||
const argv = require('yargs-parser')(process.argv.slice(2));
|
||||
|
||||
const compiler = require('./compiler');
|
||||
const randomColor = require('./randomColor');
|
||||
const pkg = require('../package.json');
|
||||
|
||||
const ESM_OUTPUT_DIR = 'es';
|
||||
const NODE_CJS_OUTPUT_DIR = 'lib';
|
||||
const SOURCE_DIR = 'src';
|
||||
const CONFIG_FILE_NAME = 'build.config.js';
|
||||
const GLOBAL_CONFIG_PATH = path.join(process.cwd(), CONFIG_FILE_NAME);
|
||||
const DEFAULT_CONFIG = {
|
||||
target: 'node',
|
||||
};
|
||||
|
||||
function genLog(pkgName) {
|
||||
return (msg) => {
|
||||
console.log(`${randomColor(pkgName)}: ${msg}`);
|
||||
};
|
||||
}
|
||||
|
||||
function genShortPath(filePath) {
|
||||
const codePath = filePath.split(`/${SOURCE_DIR}/`)[1];
|
||||
return `${SOURCE_DIR}/${codePath}`;
|
||||
}
|
||||
|
||||
function getPkgSourcePath() {
|
||||
return path.join(process.cwd(), SOURCE_DIR);
|
||||
}
|
||||
|
||||
function getOutputPath(config) {
|
||||
if (config.target === 'browser') {
|
||||
return path.join(process.cwd(), ESM_OUTPUT_DIR);
|
||||
}
|
||||
|
||||
return path.join(process.cwd(), NODE_CJS_OUTPUT_DIR);
|
||||
}
|
||||
|
||||
function getGlobalConfig() {
|
||||
if (fs.existsSync(GLOBAL_CONFIG_PATH)) {
|
||||
const userConfig = require(GLOBAL_CONFIG_PATH);
|
||||
return merge(DEFAULT_CONFIG, userConfig);
|
||||
}
|
||||
return DEFAULT_CONFIG;
|
||||
}
|
||||
|
||||
function cleanBeforeCompilerResult(log) {
|
||||
const esmOutputDir = path.join(process.cwd(), ESM_OUTPUT_DIR);
|
||||
const cjsOutputDir = path.join(process.cwd(), NODE_CJS_OUTPUT_DIR);
|
||||
if (fs.existsSync(esmOutputDir)) {
|
||||
log(chalk.gray(`Clean ${ESM_OUTPUT_DIR} directory`));
|
||||
fse.removeSync(esmOutputDir);
|
||||
}
|
||||
if (fs.existsSync(cjsOutputDir)) {
|
||||
log(chalk.gray(`Clean ${NODE_CJS_OUTPUT_DIR} directory`));
|
||||
fse.removeSync(cjsOutputDir);
|
||||
}
|
||||
}
|
||||
|
||||
function transformFile(filePath, outputPath, config, log) {
|
||||
if (/\.[jt]sx?$/.test(path.extname(filePath))) {
|
||||
try {
|
||||
const code = fs.readFileSync(filePath, 'utf-8');
|
||||
const shortFilePath = genShortPath(filePath);
|
||||
const transformedCode = compiler(code, config);
|
||||
|
||||
const type = config.target === 'browser' ? ESM_OUTPUT_DIR : NODE_CJS_OUTPUT_DIR;
|
||||
log(`Transform to ${type} for ${config.target === 'browser' ? chalk.yellow(shortFilePath) : chalk.blue(shortFilePath)}`);
|
||||
fse.outputFileSync(outputPath, transformedCode);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} else {
|
||||
fse.copySync(filePath, outputPath);
|
||||
}
|
||||
}
|
||||
|
||||
function compilerPkg(codeDir, outputDir, config, log) {
|
||||
const files = fs.readdirSync(codeDir);
|
||||
files.forEach((file) => {
|
||||
const filePath = path.join(codeDir, file);
|
||||
const outputFilePath = path.join(outputDir, file);
|
||||
const fileStats = fs.lstatSync(filePath);
|
||||
if (config.copy.includes(file)) {
|
||||
fse.copySync(filePath, outputFilePath);
|
||||
} else if (fileStats.isDirectory(filePath) && !/__tests__/.test(file)) {
|
||||
fse.ensureDirSync(outputFilePath);
|
||||
compilerPkg(filePath, outputFilePath, config, log);
|
||||
} else if (fileStats.isFile(filePath)) {
|
||||
transformFile(filePath, outputFilePath, config, log);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function watchFile(dir, outputDir, config, log) {
|
||||
chokidar
|
||||
.watch(dir, {
|
||||
ignoreInitial: true,
|
||||
})
|
||||
.on('all', (event, changeFile) => {
|
||||
// 修改的可能是一个目录,一个文件,一个需要 copy 的文件 or 目录
|
||||
const shortChangeFile = genShortPath(changeFile);
|
||||
const outputPath = changeFile.replace(dir, outputDir);
|
||||
const stat = fs.lstatSync(changeFile);
|
||||
log(`[${event}] ${shortChangeFile}`);
|
||||
if (config.resolveCopy.some((item) => changeFile.startsWith(item))) {
|
||||
fse.copySync(changeFile, outputPath);
|
||||
} else if (stat.isFile()) {
|
||||
transformFile(changeFile, outputPath, config, log);
|
||||
} else if (stat.isDirectory()) {
|
||||
compilerPkg(changeFile, outputPath, config);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function main() {
|
||||
const sourceCodeDir = getPkgSourcePath();
|
||||
const pkgName = pkg.name;
|
||||
if (fs.existsSync(sourceCodeDir)) {
|
||||
const log = genLog(pkgName);
|
||||
const config = getGlobalConfig();
|
||||
const outputDir = getOutputPath(config);
|
||||
|
||||
cleanBeforeCompilerResult(log);
|
||||
const type = config.target === 'browser' ? ESM_OUTPUT_DIR : NODE_CJS_OUTPUT_DIR;
|
||||
log(chalk.white(`Build ${type} with babel`));
|
||||
compilerPkg(sourceCodeDir, outputDir, config, log);
|
||||
if (argv.watch) {
|
||||
log(chalk.magenta(`Start watch ${SOURCE_DIR} directory...`));
|
||||
watchFile(sourceCodeDir, outputDir, config, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
52
packages/create-fes-app/templates/plugin/scripts/compiler.js
Normal file
52
packages/create-fes-app/templates/plugin/scripts/compiler.js
Normal file
@ -0,0 +1,52 @@
|
||||
// 关闭 import 规则
|
||||
/* eslint import/no-extraneous-dependencies: 0 */
|
||||
|
||||
const babel = require('@babel/core');
|
||||
|
||||
function transform(code, options) {
|
||||
const result = babel.transformSync(code, options);
|
||||
return result.code;
|
||||
}
|
||||
|
||||
function transformNodeCode(code) {
|
||||
return transform(code, {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: 'cjs',
|
||||
targets: { node: '12' },
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function transformBrowserCode(code) {
|
||||
// 因为 fes.js 在生产打包的时候,会处理所有的 node_modules 下的文件,确保不会丢失必要 polyfill
|
||||
// 因此这里不对 polyfill 进行处理,避免全局污染
|
||||
return transform(code, {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
modules: false,
|
||||
useBuiltIns: false,
|
||||
targets: { chrome: '51' },
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
function compiler(code, config) {
|
||||
if (!config.target || config.target === 'node') {
|
||||
return transformNodeCode(code);
|
||||
}
|
||||
if (config.target === 'browser') {
|
||||
return transformBrowserCode(code);
|
||||
}
|
||||
throw new Error(`config target error: ${config.target}, only can use 'node' and 'browser'`);
|
||||
}
|
||||
|
||||
module.exports = compiler;
|
@ -0,0 +1,35 @@
|
||||
/* eslint import/no-extraneous-dependencies: 0 */
|
||||
const chalk = require('chalk');
|
||||
|
||||
const colors = [
|
||||
'red',
|
||||
'green',
|
||||
'yellow',
|
||||
'blue',
|
||||
'magenta',
|
||||
'cyan',
|
||||
'gray',
|
||||
'redBright',
|
||||
'greenBright',
|
||||
'yellowBright',
|
||||
'blueBright',
|
||||
'magentaBright',
|
||||
'cyanBright',
|
||||
];
|
||||
|
||||
let index = 0;
|
||||
const cache = {};
|
||||
|
||||
module.exports = function (pkg) {
|
||||
if (!cache[pkg]) {
|
||||
const color = colors[index];
|
||||
const str = chalk[color].bold(pkg);
|
||||
cache[pkg] = str;
|
||||
if (index === colors.length - 1) {
|
||||
index = 0;
|
||||
} else {
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
return cache[pkg];
|
||||
};
|
58
packages/create-fes-app/templates/plugin/src/index.js.tpl
Normal file
58
packages/create-fes-app/templates/plugin/src/index.js.tpl
Normal file
@ -0,0 +1,58 @@
|
||||
import { join } from 'path';
|
||||
import { readFileSync } from 'fs';
|
||||
import { name } from '../package.json';
|
||||
|
||||
const namespace = 'plugin-{{{name}}}';
|
||||
|
||||
export default (api) => {
|
||||
api.describe({
|
||||
key: '{{{name}}}',
|
||||
config: {
|
||||
schema(joi) {
|
||||
return joi.object();
|
||||
},
|
||||
default: {}
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
utils: { Mustache }
|
||||
} = api;
|
||||
|
||||
const absoluteFilePath = join(namespace, 'core.js');
|
||||
|
||||
const absRuntimeFilePath = join(namespace, 'runtime.js');
|
||||
|
||||
api.onGenerateFiles(() => {
|
||||
// 运行时执行的代码全部copy到临时目录,此时不需要编译,稍后webpack会编译临时目录代码
|
||||
api.copyTmpFiles({
|
||||
namespace,
|
||||
path: join(__dirname, 'runtime'),
|
||||
ignore: ['.tpl']
|
||||
});
|
||||
|
||||
// 有些运行时代码通过配置生成,则通过tpl写入
|
||||
api.writeTmpFile({
|
||||
path: absoluteFilePath,
|
||||
content: Mustache.render(
|
||||
readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'),
|
||||
{
|
||||
}
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
if (api.builder.name === 'vite') {
|
||||
// 处理vite构建器
|
||||
} else if(api.builder.name === 'webpack') {
|
||||
// 处理webpack构建器
|
||||
}
|
||||
|
||||
// 注册运行时插件
|
||||
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
|
||||
|
||||
// 注册代码提示
|
||||
api.addConfigType(() => ({
|
||||
source: name,
|
||||
}));
|
||||
};
|
@ -0,0 +1 @@
|
||||
// 通过配置生成的代码
|
@ -0,0 +1,5 @@
|
||||
// 配置运行时插件
|
||||
|
||||
export function onAppCreated({ app }) {
|
||||
console.log(app);
|
||||
}
|
10
packages/create-fes-app/templates/plugin/types.d.ts
vendored
Normal file
10
packages/create-fes-app/templates/plugin/types.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import {} from '@fesjs/fes';
|
||||
declare module "@fesjs/fes" {
|
||||
interface PluginBuildConfig {
|
||||
|
||||
}
|
||||
|
||||
interface PluginRuntimeConfig {
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user