From 572d1551e62891ad422eeffe4f833e079c993bc8 Mon Sep 17 00:00:00 2001 From: zhangyuang Date: Sun, 23 Jun 2019 20:10:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=8D=E6=9E=84yk-cli?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/README.md | 11 +- example/ssr-with-js/README.md | 166 ++---------------- packages/yk-cli/.gitignore | 4 - packages/yk-cli/README.md | 126 ++----------- packages/yk-cli/help.txt | 12 -- packages/yk-cli/package.json | 11 +- packages/yk-cli/src/app.ts | 37 ---- packages/yk-cli/src/cache.ts | 55 ++---- packages/yk-cli/src/check.ts | 33 ++++ packages/yk-cli/src/config.ts | 31 ++-- packages/yk-cli/src/help.ts | 14 -- packages/yk-cli/src/index.ts | 87 ++++----- packages/yk-cli/src/interface/option.ts | 2 +- packages/yk-cli/src/package.ts | 13 +- packages/yk-cli/src/update.ts | 59 ++----- packages/yk-cli/src/util/fileconfig.ts | 9 - packages/yk-cli/src/util/index.ts | 74 ++++++++ packages/yk-cli/src/util/readFileList.ts | 30 ---- packages/yk-cli/src/util/render.ts | 19 -- packages/yk-cli/src/util/versionCompare.ts | 51 ------ packages/yk-cli/src/util/versionEffective.ts | 48 ----- packages/yk-cli/src/webcomponent.ts | 64 ------- packages/yk-cli/src/webpackconfig.ts | 31 ++-- .../tpl/build/webpack.config.base.js.nj | 26 --- packages/yk-cli/tpl/package.json.nj | 9 +- packages/yk-cli/tpl/web/assets/common.css.nj | 13 -- packages/yk-cli/tpl/web/layout/index.css.nj | 22 --- packages/yk-cli/tpl/web/layout/index.js.nj | 26 --- .../tpl/web/layout/index.module.style.d.ts.nj | 2 - packages/yk-cli/tpl/web/layout/index.tsx.nj | 36 ---- .../yk-cli/tpl/web/page/index/index.css.nj | 39 ---- .../yk-cli/tpl/web/page/index/index.js.nj | 52 ------ .../web/page/index/index.module.style.d.ts.nj | 2 - .../yk-cli/tpl/web/page/index/index.tsx.nj | 105 ----------- .../yk-cli/tpl/web/page/news/index.css.nj | 9 - packages/yk-cli/tpl/web/page/news/index.js.nj | 37 ---- .../web/page/news/index.module.scss.d.ts.nj | 1 - .../yk-cli/tpl/web/page/news/index.tsx.nj | 73 -------- .../yk-cli/tpl/web/page/news/layout.css.nj | 22 --- .../yk-cli/tpl/web/page/news/layout.js.nj | 20 --- packages/yk-cli/types/check.d.ts | 9 + packages/yk-cli/types/config.d.ts | 2 +- packages/yk-cli/types/interface/answers.d.ts | 10 ++ packages/yk-cli/types/interface/option.d.ts | 2 +- packages/yk-cli/types/package.d.ts | 2 +- packages/yk-cli/types/update.d.ts | 3 +- packages/yk-cli/types/util/fileconfig.d.ts | 8 - packages/yk-cli/types/util/index.d.ts | 25 +++ packages/yk-cli/types/util/readFileList.d.ts | 2 +- .../yk-cli/types/util/versionEffective.d.ts | 9 - packages/yk-cli/types/webpackconfig.d.ts | 2 +- 51 files changed, 291 insertions(+), 1264 deletions(-) delete mode 100644 packages/yk-cli/help.txt delete mode 100644 packages/yk-cli/src/app.ts create mode 100644 packages/yk-cli/src/check.ts delete mode 100644 packages/yk-cli/src/help.ts delete mode 100644 packages/yk-cli/src/util/fileconfig.ts create mode 100644 packages/yk-cli/src/util/index.ts delete mode 100644 packages/yk-cli/src/util/readFileList.ts delete mode 100644 packages/yk-cli/src/util/render.ts delete mode 100644 packages/yk-cli/src/util/versionCompare.ts delete mode 100644 packages/yk-cli/src/util/versionEffective.ts delete mode 100644 packages/yk-cli/src/webcomponent.ts delete mode 100755 packages/yk-cli/tpl/web/assets/common.css.nj delete mode 100644 packages/yk-cli/tpl/web/layout/index.css.nj delete mode 100644 packages/yk-cli/tpl/web/layout/index.js.nj delete mode 100644 packages/yk-cli/tpl/web/layout/index.module.style.d.ts.nj delete mode 100644 packages/yk-cli/tpl/web/layout/index.tsx.nj delete mode 100644 packages/yk-cli/tpl/web/page/index/index.css.nj delete mode 100644 packages/yk-cli/tpl/web/page/index/index.js.nj delete mode 100644 packages/yk-cli/tpl/web/page/index/index.module.style.d.ts.nj delete mode 100644 packages/yk-cli/tpl/web/page/index/index.tsx.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/index.css.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/index.js.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/index.module.scss.d.ts.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/index.tsx.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/layout.css.nj delete mode 100644 packages/yk-cli/tpl/web/page/news/layout.js.nj create mode 100644 packages/yk-cli/types/check.d.ts create mode 100644 packages/yk-cli/types/interface/answers.d.ts delete mode 100644 packages/yk-cli/types/util/fileconfig.d.ts create mode 100644 packages/yk-cli/types/util/index.d.ts diff --git a/docs/README.md b/docs/README.md index 28d757bd..a264172d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,10 +9,10 @@ features: details: 支持HMR,同时支持本地开发以及生产环境CSR/SSR两种渲染模式无缝切换,支持定制特定组件的渲染模式 - title: 美 details: 配置非黑盒,且一切关键位置皆可通过config.default.js来配置 -footer: MIT Licensed | Copyright © 2017-present +footer: MIT Licensed | Copyright © 2019-present --- -## Getting started +# Getting started ```bash $ npm install yk-cli -g @@ -23,7 +23,7 @@ $ npm start $ open http://localhost:7001 ``` -## 用法 +# 用法 - render是react的视图渲染方法 - getInitialProps是获取数据方法,将返回值赋值给组件状态 @@ -44,8 +44,11 @@ Page.getInitialProps = async (ctx) => { export default Page ``` -## 社区交流 +# 社区交流 | Pull Request | Github Issue | 钉钉群 | | ------------------------------------------------------------ | ------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | [egg-react-ssr/pulls](https://github.com/ykfe/egg-react-ssr/pulls) | [egg-react-ssr/issues](https://github.com/ykfe/egg-react-ssr/issues) | | + +推荐使用[umijs](https://umijs.org/zh/),最新版已经支持SSR以及PreRender。实现方式与本骨架一致,两者不冲突,互相补位,分别适用于开箱即用的场景以及更好的定制化应用场景。 + diff --git a/example/ssr-with-js/README.md b/example/ssr-with-js/README.md index 62156605..98ee5268 100755 --- a/example/ssr-with-js/README.md +++ b/example/ssr-with-js/README.md @@ -1,5 +1,6 @@ # Egg + React + SSR应用骨架 -[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) + +详细用法实现请查看[官方文档](http://ykfe.net) # Getting Start @@ -16,158 +17,17 @@ $ open http://localhost:7001 # 功能/特性 -## 已完成 - -- 基于cra脚手架开发,由cra开发的React App可无缝迁移,如果你熟悉cra的配置,上手成本几乎为0 -- 小而美,相比于beidou,next.js这样的高度封装方案,我们的实现原理和开发模式一目了然 -- 同时支持SSR以及CSR两种开发模式,本地开发环境以及线上环境皆可无缝切换两种渲染模式 -- 统一前端路由与服务端路由,无需重复编写路由文件配置 -- 支持切换路由时自动获取数据 -- 支持本地开发HMR -- 稳定性经过线上大规模应用验证,可提供性能优化方案 -- 支持tree shaking以及打包去重依赖,使得打包的bundle非常小,为同样复杂度的next.js项目的0.4倍 -- 支持csr/ssr自定义layout,无需通过path来手动区分 -- 支持选择某个具体的组件在客户端还是服务端进行渲染 - -## 开发中 - -- 配套[TypeScript](https://github.com/ykfe/egg-react-ssr-typescript)版本的实现 -- 配套serverless版本的实现 - -# 获取数据 - -定义组件的静态方法getInitialProps,获取数据的逻辑将统一在这个方法中执行。 - -当页面初始化加载时,getInitialProps只会加载在服务端。只有当路由跳转(Link组件跳转或 API 方法跳转)时,客户端才会执行getInitialProps。 - -注意:getInitialProps将不能使用在子组件中。只能使用在pages页面中。 - -getInitialProps入参对象的属性如下: - -ctx: Node应用请求的上下文(仅在SSR阶段可以获取) - -Router Props: 路由信息,包括pathname以及Router params等信息,详细信息参考react-router文档 - -# 目录结构 - -``` -├── README.md -├── app // egg核心目录 -│   ├── controller -│   ├── extend -│   ├── middleware -│   └── router.js // egg路由文件,无特殊需求不需要修改内容 -├── app.js // egg 启动入口文件 -├── build // webpack配置目录 -│   ├── env.js -│   ├── jest -│   ├── paths.js -│   ├── util.js -│   ├── webpack.config.base.js // 通用的webpack配置 -│   ├── webpack.config.client.js // webpack客户端打包配置 -│   └── webpack.config.server.js // webpack服务端打包配置 -├── config // egg 配置文件目录 -│   ├── config.daily.js -│   ├── config.default.js -│   ├── config.local.js -│   ├── config.prod.js -│   ├── config.staging.js -│   ├── plugin.js -│   └── plugin.local.js -├── dist // build生成静态资源文件目录 -│   ├── Page.server.js // 服务端打包后文件(即打包后的serverRender方法) -│   └── static // 前端打包后静态资源目录 -└── web // 前端文件目录 - ├── assets - │   └── common.less - ├── entry.js // webpack打包入口文件,分环境导出不同配置 - ├── index.html // 页面骨架模版 - ├── layout - │   ├── index.js // 页面布局 - │   └── index.less - └── page - ├── index - └── news -``` - -# npm scripts - -``` -$ npm start // 启动监听7001端口,建议使用方式,同时启动服务端渲染 + 客户端hydrate -$ npm run ssr // 启动监听7001端口,只启动服务端渲染,此时仅服务端直出html,没有与客户端混合的步骤 -$ npm run csr // 启动监听8000端口,只启动客户端渲染,相当于传统的cra脚手架开发模式 -$ npm run prod // 模拟SSR应用生产环境 -$ npm run build // 打包服务端以及客户端资源文件 -$ npm run analyze // 可视化分析客户端打包的资源详情 -``` - -# config.default.js 文件配置 - -为了足够灵活使用,这里我们将一些关键项提供可配置的选项,可根据实际需要来配置,如无特殊必要,使用默认配置即可。 - -```js -const resolvePath = (path) => require('path').resolve(process.cwd(), path) - -module.exports = { - keys: 'eggssr', - type: 'ssr', // 指定运行类型可设置为csr切换为客户端渲染 - static: { - // 设置Node应用的静态资源目录,为了生产环境读取静态资源文件 - prefix: '/', - dir: resolvePath('dist') - }, - routes: [ - // 前后端统一使用的路由配置文件,防止重复编写相同的路由 - { - path: '/', // 请求的path - exact: true, // 是否精确匹配 - Component: () => (require('@/page/index').default), // 这里使用一个function包裹为了让它延迟require, 否则Node环境无法识别前端组件中用到的import关键字会报错 - controller: 'page', // 需要调用的controller - handler: 'index' // 需要调用的controller中具体的method - }, - { - path: '/news/:id', - exact: true, - Component: () => (require('@/page/news').default), - controller: 'page', - handler: 'index' - } - ], - template: resolvePath('web/index.html'), // 使用的模版文件路径 - injectCss: (chunkName) => ([ - `/static/css/${chunkName}.chunk.css` - ]), // 客户端需要加载的静态css文件资源 - injectScript: (chunkName) => ([ - ``, - ``, - `` - ]), // 客户端需要加载的静态js文件资源 - serverJs: (chunkName) => resolvePath(`dist/${chunkName}.server.js`) // 服务端需要使用的打包后的serverRender方法js文件的路径 -} -``` - -# 执行流程 - -![](https://gw.alicdn.com/tfs/TB11BwkX8Gw3KVjSZFDXXXWEpXa-2050-1502.jpg) - -# 与其他方案的对比 - -- 与[easy-team](https://github.com/ykfe/egg-react-ssr/wiki/与easy-team实现方案的对比)方案的对比 -- 与[next.js](https://github.com/ykfe/egg-react-ssr/wiki/与next.js实现方案的对比)方案的对比 - -# 答疑群 - -虽然我们已经尽力检查了一遍应用,但仍有可能有疏漏的地方,如果你在使用过程中发现任何问题或者建议,欢迎提[issue](https://github.com/ykfe/egg-react-ssr/issues)或者[PR](https://github.com/ykfe/egg-react-ssr/pulls) -欢迎直接扫码加入钉钉群 - - -## Contributors +- [x] 基于cra脚手架开发,由cra开发的React App可无缝迁移,如果你熟悉cra的配置,上手成本几乎为0 +- [x] 小而美,相比于beidou,next.js这样的高度封装方案,我们的实现原理和开发模式一目了然 +- [x] 同时支持SSR以及CSR两种开发模式,本地开发环境以及线上环境皆可无缝切换两种渲染模式 +- [x] 统一前端路由与服务端路由,无需重复编写路由文件配置 +- [x] 支持切换路由时自动获取数据 +- [x] 支持本地开发HMR +- [x] 稳定性经过线上大规模应用验证,可提供性能优化方案 +- [x] 支持tree shaking以及打包去重依赖,使得打包的bundle非常小,为同样复杂度的next.js项目的0.4倍 +- [x] 支持csr/ssr自定义layout,无需通过path来手动区分 +- [ ] 配套[TypeScript](https://github.com/ykfe/egg-react-ssr-typescript)版本的实现 +- [ ] 配套serverless版本的实现 -Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): - - -
LeonCheung
LeonCheung

💻
狼叔
狼叔

💻
Xu Zhiyong
Xu Zhiyong

🐛
zhaoxingyue
zhaoxingyue

💻
zhushijie
zhushijie

💻
- -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/packages/yk-cli/.gitignore b/packages/yk-cli/.gitignore index da1ced07..91645a3e 100644 --- a/packages/yk-cli/.gitignore +++ b/packages/yk-cli/.gitignore @@ -64,7 +64,3 @@ package-lock.json cache/** bin - -javascript.version.json - -typescript.version.json \ No newline at end of file diff --git a/packages/yk-cli/README.md b/packages/yk-cli/README.md index a9c61350..3d03d57e 100644 --- a/packages/yk-cli/README.md +++ b/packages/yk-cli/README.md @@ -1,122 +1,20 @@ # yk-cli +用于快速创建一个Egg + React + SSR 应用的脚手架 -### 安装 - -* npm install . -g - -* npm install yk-cli -g - - -### 命令介绍 - -* 创建 ykcli init || ykcli init 应用名(可选) - -* 帮助 ykcli help - -* 增加组件 ykcli generate component 组件名 || ykcli gc 组件名 (待实现) - -### 开发模式 - -* 开发 npm run dev - -* 构建 npm run build - -* 发布 npm publish - -### 注释工具 - -* Document this (https://marketplace.visualstudio.com/items?itemName=joelday.docthis) - -### vscode 调试文件 - -* .vscode/launch.json - -```json - -{ - "version": "0.2.0", - "configurations": [{ - "type": "node", - "request": "launch", - "name": "Launch via NPM", - "runtimeExecutable": "npm", - "cwd": "${workspaceRoot}", - "console": "integratedTerminal", - "protocol": "inspector", - "restart": true, - "windows": { - "runtimeExecutable": "npm.cmd" - }, - "runtimeArgs": [ - "start", - "init" - ], - "port": 19229 - }, - { - "type": "node", - "request": "launch", - "name": "node", - "program": "${workspaceRoot}/bin/index.js", - "sourceMaps": true, - "cwd": "${workspaceRoot}", - "runtimeArgs": [ - "--inspect-brk=19229" - ], - "console": "integratedTerminal", - "protocol": "inspector", - "restart": true, - "args": [ - "init" - ], - "port": 19229 - } - ] -} +# Getting Start +如何使用 ``` - -### 文件结构 - +$ npm install yk-cli -g +$ ykcli init +$ cd +$ npm i +$ npm start +$ open http://localhost:7001 ``` -. -├── LICENSE -├── README.md -├── bin // 输出的运行的Js命令行文件 -├── help.txt // 命令行帮助输出内容 -├── package.json -├── src // 开发源码文件 -│   ├── app.ts // 初始化app -│   ├── cache.ts // 处理缓存 -│   ├── config.ts // 应用配置选项 -│   ├── help.ts // 帮助显示 -│   ├── index.ts // 命令行入口 -│   ├── interface -│   │   └── option.ts // 应用配置接口类型 -│   ├── package.ts -│   ├── util -│   │   ├── fileconfig.ts // 获取文件配置 -│   │   ├── readFileList.ts // 递归文件夹文件 -│   │   ├── render.ts // 模板渲染方法 -│   │   ├── versionCompare.ts // 缓存与线上版本比对 -│   │   └── versionEffective.ts // 获取线上版本 判断缓存是否有效 -│   ├── webcomponent.ts // 编译web下组件模板 -│   └── webpackconfig.ts // 编译webpack -├── tpl // 编译模板 -│   ├── build // webpack模板文件 -│   │   ├── paths.js.nj -│   │   ├── util.js.nj -│   │   ├── webpack.config.base.js.nj -│   │   ├── webpack.config.client.js.nj -│   │   └── webpack.config.server.js.nj -│   ├── package.json.nj // package.json模板文件 -│   └── web // web下 组件模板(参考路径必须和example中路径一致才可以编译生效) -│   ├── assets -│   ├── layout -│   └── page -├── tsconfig.json // ts编译选项 -└── types // 编译类型 -``` \ No newline at end of file +# Guide + +更详细的使用说明请查看[官方文档](http://ykfe.net) \ No newline at end of file diff --git a/packages/yk-cli/help.txt b/packages/yk-cli/help.txt deleted file mode 100644 index 16b8b3d3..00000000 --- a/packages/yk-cli/help.txt +++ /dev/null @@ -1,12 +0,0 @@ - - Usage: ykcli - - - Commands: - - init create a new project powered by yk-cli - help help for detailed usage of yk-cli information - - - If you have any problems, do not hesitate to file an issue: - https://github.com/ykfe/yk-cli/issues \ No newline at end of file diff --git a/packages/yk-cli/package.json b/packages/yk-cli/package.json index fdaf1657..50be0644 100644 --- a/packages/yk-cli/package.json +++ b/packages/yk-cli/package.json @@ -1,7 +1,7 @@ { "name": "yk-cli", - "version": "1.0.13", - "description": "react ssr + csr cli", + "version": "1.0.15", + "description": "ykcli for ssr", "main": "./bin/index.js", "types": "types/index.d.ts", "scripts": { @@ -28,12 +28,15 @@ "download-git-repo": "^2.0.0", "inquirer": "6.3.1", "nunjucks": "^3.2.0", - "ora": "^3.4.0" + "ora": "^3.4.0", + "shelljs": "^0.8.3", + "yargs": "^13.2.4" }, "devDependencies": { "@types/inquirer": "^6.0.3", - "@types/node": "^10.12.10", "@types/nunjucks": "^3.1.1", + "@types/shelljs": "^0.8.5", + "@types/yargs": "^13.0.0", "tslint": "^5.17.0", "tslint-config-standard": "^8.0.1", "typescript": "^3.5.2" diff --git a/packages/yk-cli/src/app.ts b/packages/yk-cli/src/app.ts deleted file mode 100644 index 8a9c43a7..00000000 --- a/packages/yk-cli/src/app.ts +++ /dev/null @@ -1,37 +0,0 @@ - -import { spawn } from 'child_process' -import { Optional } from './interface/option' -import inquirer from 'inquirer' -import fs from 'fs' - -/** - * 应用初始化函数 - * - * @export - * @param {Optional} option 应用全局配置 - * @returns {Promise} - */ -export function init_app (option: Optional): Promise { - return new Promise((resolve, reject) => { - /** 如果文件重复则提示 是否删除 对应 create react app 的交互 */ - if (fs.existsSync(`./${option.appname}`)) { - inquirer.prompt([{ - type: 'confirm', - message: `当前文件夹下含有您要创建 ${option.appname} 的应用名称文件,是否强制删除文件 继续初始化?`, - name: 'file' - }]).then((answers: any) => { - if (answers.file) { - const task = spawn(`rm -rf ./${option.appname}`, [], { cwd: `./`, shell: true }) - task.on('close', (code: number) => { - console.log(`原文件已经成功删除....`) - resolve() - }) - } else { - reject() - } - }) - } else { - resolve() - } - }) -} diff --git a/packages/yk-cli/src/cache.ts b/packages/yk-cli/src/cache.ts index f6682450..ad202fa1 100644 --- a/packages/yk-cli/src/cache.ts +++ b/packages/yk-cli/src/cache.ts @@ -1,12 +1,6 @@ -import { getVersionEffective } from './util/versionEffective' +import { downloadPromise, resolveApp, getVersionEffective } from './util/index' import { Optional } from './interface/option' -import { versionlog } from './util/versionCompare' -import { config } from './util/fileconfig' -import { spawn } from 'child_process' -import path from 'path' - -const download = require('download-git-repo') - +import shell from 'shelljs' /** * 缓存管理 * @@ -14,39 +8,14 @@ const download = require('download-git-repo') * @param {Optional} option 应用全局配置 * @returns {Promise} */ -export function cacheMange (option: Optional): Promise { - - return getVersionEffective(option) - .then((value) => new Promise((resolve, reject) => { - /** 如果版本不一致 则直接更新缓存 */ - if (!value) { - download(`github:ykfe/egg-react-ssr#master`, path.resolve(__dirname, '../cache'), (err: any) => { - if (!err) { - const packagejsonPath = path.resolve(__dirname, `../cache/example/ssr-with-${option.language === 'javascript' ? 'js' : 'ts'}/package.json`) - const version = require(packagejsonPath).version - versionlog(option.language!, version) - resolve() - } else { - console.log('download failed') - console.log(err) - reject() - } - }) - } else { - resolve() - } - })).then(() => new Promise((resolve, reject) => { - /** 将缓存中的对应的项目内容拷贝至 '项目名称' 文件夹 */ - const task = spawn(`cp -rf ${__dirname}/../cache/example/ssr-with-${option.language === 'javascript' ? 'js' : 'ts'} ./`, [], { cwd: `./`, shell: true }) - task.on('close', (_code: number) => { - resolve() - }) - })).then(() => new Promise((resolve, reject) => { - /** 当前执行目录下修改创建 '项目名称' 文件夹 */ - const task = spawn(`mv ssr-with-${option.language === 'javascript' ? 'js' : 'ts'} ${option.appname}`, [], { cwd: `./`, shell: true }) - task.on('close', (code: number) => { - console.log('\n 创建项目文件夹.....') - resolve() - }) - })) +export async function cacheMange (option: Optional): Promise { + const useCache = await getVersionEffective(option) + const language = option.language === 'javascript' ? 'js' : 'ts' + // 如果没有缓存可用则拉取最新代码 + if (!useCache) { + await downloadPromise('github:ykfe/egg-react-ssr#master', resolveApp('./cache')) + } + const example = resolveApp(`./cache/example/ssr-with-${language}`) + shell.cp('-rf', example, './') + shell.mv(`./ssr-with-${language}`, `./${option.appName}`) } diff --git a/packages/yk-cli/src/check.ts b/packages/yk-cli/src/check.ts new file mode 100644 index 00000000..78920159 --- /dev/null +++ b/packages/yk-cli/src/check.ts @@ -0,0 +1,33 @@ +import { processError } from './util/index' +import { Optional } from './interface/option' +import inquirer from 'inquirer' +import fs from 'fs' +import shell from 'shelljs' + +/** + * 应用初始化函数 + * + * @export + * @param {Optional} option 应用全局配置 + * @returns {Promise} + */ +export function checkRepeat (option: Optional): Promise { + const { appName } = option + return new Promise((resolve, reject) => { + // 如果文件重复则提示 是否删除 对应 create react app 的交互 + if (fs.existsSync(`./${appName}`)) { + inquirer.prompt([{ + type: 'confirm', + message: `当前文件夹下含有您要创建 ${appName} 的应用名称文件,是否强制删除文件 继续初始化?`, + name: 'delete', + default: 'Yes' + }]).then(async (answers: any) => { + if (answers.delete) { + shell.rm('-rf', `./${appName}`) + console.log(`原文件已经成功删除...`) + resolve() + } else process.exit() + }) + } else resolve() + }).catch(err => processError(err)) +} diff --git a/packages/yk-cli/src/config.ts b/packages/yk-cli/src/config.ts index 6125ac7e..384d9003 100644 --- a/packages/yk-cli/src/config.ts +++ b/packages/yk-cli/src/config.ts @@ -1,3 +1,4 @@ +import { processError } from './util/index' import { Optional } from './interface/option' import inquirer from 'inquirer' @@ -8,37 +9,25 @@ import inquirer from 'inquirer' * @param {Optional} option * @returns {Promise} */ -export function appconfig (option: Optional): Promise { +export function getConfig (option: Optional): Promise { return new Promise((resolve, reject) => { inquirer.prompt([{ type: 'input', - message: '您创建的应用名称:', - name: 'appname', - default: option.command && option.command.length > 0 ? String(option.command[0]) : 'app' + message: '应用名称:', + name: 'appName', + default: option.appName }, { type: 'list', - message: '使用的开发语言', + message: '开发语言', name: 'language', default: 'javascript', choices: [ - 'javascript', - 'typescript(开发中)' - ] - }, { - type: 'list', - message: '是否使用样式预处理器:', - name: 'style', - default: 'less', - choices: [ - 'less', - 'sass', - 'css' + 'javascript' + // 'typescript(开发中)' ] }]).then((answers: any) => { - option.appname = answers.appname - option.style = answers.style - option.language = answers.language + Object.assign(option, answers) resolve() }) - }) + }).catch(err => processError(err)) } diff --git a/packages/yk-cli/src/help.ts b/packages/yk-cli/src/help.ts deleted file mode 100644 index 229fdb34..00000000 --- a/packages/yk-cli/src/help.ts +++ /dev/null @@ -1,14 +0,0 @@ -import fs from 'fs' - -/** - * 项目帮助提示 - * - * @export - * @returns {Promise} - */ -export function help (): Promise { - return new Promise((resolve, reject) => { - let content = fs.readFileSync(`${__dirname}/../help.txt`).toString('utf8') - console.log(content) - }) -} diff --git a/packages/yk-cli/src/index.ts b/packages/yk-cli/src/index.ts index ff6031a6..ad2f7c00 100644 --- a/packages/yk-cli/src/index.ts +++ b/packages/yk-cli/src/index.ts @@ -2,61 +2,42 @@ import ora from 'ora' import { Optional } from './interface/option' -import { appconfig } from './config' -import { init_app } from './app' -import { packagejson } from './package' -import { webpack } from './webpackconfig' -import { help } from './help' +import { getConfig } from './config' +import { checkRepeat } from './check' +import { processPackage } from './package' +import { processWebpack } from './webpackConfig' import { cacheMange } from './cache' -import { component } from './webcomponent' -import { updatelocal } from './update' +import { update } from './update' +import yargs from 'yargs' -const spinner = ora('正在下载模版...') -/** 总会话函数 */ -const generator = (argv: string[]): void => { - /** 所有命令参数 */ - let optionlist = argv - let option: Optional = {} - option.action = optionlist[0] - option.command = optionlist.slice(1) +const spinner = ora('应用初始化中') - const session = async () => { - let action = option.action - try { - switch (action) { - /** 构建项目 */ - case 'init': - /** 自检更新当前脚手架是否最新 */ - await updatelocal(option) - /** 问询APP配置 */ - await appconfig(option) - /** 构建应用 */ - await init_app(option) - spinner.start() - /** 缓存比对 */ - await cacheMange(option) - /** 处理 package.json */ - await packagejson(option) - /** 处理 webpack */ - await webpack(option) - /** 处理 组件 */ - if ((option.language === 'javascript' && option.style !== 'less') || (option.language === 'typescript' && option.style !== 'sass')) { - await component(option) - } - spinner.succeed() - console.log(`项目安装成功!`) - break - /** 项目帮助 */ - case 'help': - await help() - break - } - } catch (ex) { - console.log(ex) +yargs + .command('init [appName]', 'init the program', {}, async (argv: any) => { + const option: Optional = { + appName: argv.appName || 'app' } - } + // 自检更新当前脚手架是否最新 + await update() + // 问询APP配置 + await getConfig(option) + // 判断当前appName是否已存在 + await checkRepeat(option) + // 显示loading + spinner.start() + // 缓存比对 + await cacheMange(option) + // 处理 package.json + processPackage(option) + // 处理 webpack + processWebpack(option) - session() -} - -generator(process.argv.slice(2)) + spinner.succeed() + process.exit() + }) + .demandCommand(1, 'You need at least one command before moving on') + .option('version', { + alias: 'v', + default: false + }) + .parse() diff --git a/packages/yk-cli/src/interface/option.ts b/packages/yk-cli/src/interface/option.ts index 7756a532..71aab777 100644 --- a/packages/yk-cli/src/interface/option.ts +++ b/packages/yk-cli/src/interface/option.ts @@ -9,7 +9,7 @@ export interface Optional { tool?: string /** 应用名称 */ - appname?: string + appName?: string /** 样式预处理 */ style?: 'less' | 'sass' | 'css' diff --git a/packages/yk-cli/src/package.ts b/packages/yk-cli/src/package.ts index aa40de2f..2cc3de3e 100644 --- a/packages/yk-cli/src/package.ts +++ b/packages/yk-cli/src/package.ts @@ -1,7 +1,6 @@ +import { renderTemplate } from './util/index' import { Optional } from './interface/option' -import { renderTemplate } from './util/render' import path from 'path' - /** * package.json * 修改模式 @@ -9,11 +8,7 @@ import path from 'path' * @param {Optional} option 应用全局配置 * @returns {Promise} */ -export function packagejson (option: Optional): Promise { - return new Promise((resolve, reject) => { - const tplpath = path.resolve(__dirname, '../tpl/package.json.nj') - renderTemplate(tplpath, `./${option.appname}/package.json`, option) - console.log('原项目配置修改成功.....') - resolve() - }) +export function processPackage (option: Optional): void { + const tplpath = path.resolve(__dirname, '../tpl/package.json.nj') + renderTemplate(tplpath, `./${option.appName}/package.json`, option) } diff --git a/packages/yk-cli/src/update.ts b/packages/yk-cli/src/update.ts index 0bbb17c0..ce152ea4 100644 --- a/packages/yk-cli/src/update.ts +++ b/packages/yk-cli/src/update.ts @@ -1,7 +1,7 @@ -import { spawn } from 'child_process' -import { Optional } from './interface/option' -import path from 'path' - +import { getPromise, execPromise, processError, resolveApp } from './util/index' +import ora from 'ora' +const spinner = ora('发现本地版本较旧,尝试更新yk-cli脚手架') +const url = 'https://raw.githubusercontent.com/ykfe/egg-react-ssr/master/packages/yk-cli/package.json' /** * 判断NPM包自动更新 * @@ -9,40 +9,19 @@ import path from 'path' * @param {Optional} option 全局应用配置 * @returns {Promise} */ -export function updatelocal (option: Optional): Promise { - return new Promise((resolve, reject) => { - const task = spawn(`npm view yk-cli version`, [], { cwd: `./`, shell: true }) - let version: any = null - task.stdout.on('data', data => { - version = data - }) - task.on('close', (code: number) => { - resolve(version.toString().trim()) - }) - }).then( - data => - new Promise((resolve, reject) => { - const filepath = path.resolve(__dirname, '../package.json') - const localversion = require(filepath).version - /** 成功拿到版本号 且 版本号与本地版本号不一致则执行更新 */ - if (data && data !== localversion) { - console.log('发现本地版本较旧,尝试更新yk-cli脚手架') - const task = spawn(`npm i yk-cli@${data} -g`, [], { - cwd: `./`, - shell: true - }) - task.stdout.on('data', (data) => { - console.log(data.toString('utf-8')) - }) - task.on('close', (code: number) => { - console.log( - `更新完毕... 请您重新执行 ykcli init` - ) - process.exit() - }) - } else { - resolve() - } - }) - ) +export function update (): Promise { + return new Promise(async (resolve, reject) => { + const { version } = await getPromise(url) + resolve(version.trim()) + }).then(async version => { + const localVersion = require(resolveApp('./package.json')).version.trim() + // 成功拿到版本号 且 版本号与本地版本号不一致则执行更新 + if (version !== localVersion) { + spinner.start() + const { stdout } = await execPromise(`npm i -g --registry=https://registry.npm.taobao.org yk-cli@${version}`) + spinner.succeed() + console.log(stdout, `更新完毕... 请您重新执行 ykcli init`) + process.exit() + } + }).catch(err => processError(err)) } diff --git a/packages/yk-cli/src/util/fileconfig.ts b/packages/yk-cli/src/util/fileconfig.ts deleted file mode 100644 index b8bc98b3..00000000 --- a/packages/yk-cli/src/util/fileconfig.ts +++ /dev/null @@ -1,9 +0,0 @@ - -/** - * 脚手架参数 - */ -export const config = { - ts_url: 'https://raw.githubusercontent.com/zhusjfaker/egg-react-ssr/backup/example/ssr-with-ts/package.json', - js_url: 'https://raw.githubusercontent.com/ykfe/egg-react-ssr/master/example/ssr-with-js/package.json', - branch: 'backup' -} diff --git a/packages/yk-cli/src/util/index.ts b/packages/yk-cli/src/util/index.ts new file mode 100644 index 00000000..fd607902 --- /dev/null +++ b/packages/yk-cli/src/util/index.ts @@ -0,0 +1,74 @@ +import { promisify } from 'util' +import { exec } from 'child_process' +import https from 'https' +import path from 'path' +import { Optional } from '../interface/option' +import fs from 'fs' +import nunjucks from 'nunjucks' + +const download = require('download-git-repo') +const tsUrl = 'https://raw.githubusercontent.com/zhusjfaker/egg-react-ssr/backup/example/ssr-with-ts/package.json' +const jsUrl = 'https://raw.githubusercontent.com/ykfe/egg-react-ssr/master/example/ssr-with-js/package.json' + +export const processError = (err: string) => { + if (err) { + console.log('err', err) + process.exit() + } +} + +export const execPromise = promisify(exec) + +export const downloadPromise = promisify(download) + +export const resolveApp = (source: string) => { + // 以根目录为基准 + return path.resolve(__dirname, `../../${source}`) +} + +export const getPromise: object = (url: string) => { + return new Promise((resolve, reject) => { + let data: string = '' + https.get(url, res => { + res.on('data', (chunk: Buffer) => { data += chunk.toString() }) + res.on('end', () => { + resolve(JSON.parse(data)) + }) + }).on('error', () => reject()) + }) +} + +/** + * http + * 缓存判断是否有效处理 + * @export + * @param {Optional} option + * @returns {Promise} + */ +export async function getVersionEffective (option: Optional): Promise { + if (fs.existsSync(resolveApp('./cache'))) { + const url = option.language === 'typescript' ? tsUrl : jsUrl + const language = option.language === 'javascript' ? 'js' : 'ts' + const { version } = await getPromise(url) + const localVersion = require(resolveApp(`./cache/example/ssr-with-${language}/package.json`)).version.trim() + // 如果版本一样就不用更新 + return version.trim() === localVersion + } + return false +} + +/** + * 渲染 Nunjuncks + * + * @export + * @param {string} template 模板路径 + * @param {string} file 写入文件 + * @param {Optional} content 写入内容 + */ +export function renderTemplate (template: string, file: string, content: Optional): void { + if (fs.existsSync(template)) { + const templateContent = fs.readFileSync(template).toString() + const result = nunjucks.renderString(templateContent, content) + fs.writeFileSync(file, result) + } +} diff --git a/packages/yk-cli/src/util/readFileList.ts b/packages/yk-cli/src/util/readFileList.ts deleted file mode 100644 index 0f3e37d3..00000000 --- a/packages/yk-cli/src/util/readFileList.ts +++ /dev/null @@ -1,30 +0,0 @@ -import fs from 'fs' -import path from 'path' - -/** - * 递归文件夹下所有文件 - * - * @export - * @param {string} dir 文件夹 - * @param {string[]} [filesList=[]] 初始内容 - * @param {(string | null)} [ext=null] 后缀过滤 - * @returns - */ -export function readFileList (dir: string, filesList: string[] = [], ext: string | null = null) { - const files = fs.readdirSync(dir) - files.forEach((item, index) => { - let fullPath = path.join(dir, item) - const stat = fs.statSync(fullPath) - if (stat.isDirectory()) { - readFileList(path.join(dir, item), filesList, ext) // 递归读取文件 - } else { - if (ext && item.indexOf(ext) > -1) { - filesList.push(fullPath) - } else if (!ext) { - filesList.push(fullPath) - } - - } - }) - return filesList -} diff --git a/packages/yk-cli/src/util/render.ts b/packages/yk-cli/src/util/render.ts deleted file mode 100644 index f7ebc476..00000000 --- a/packages/yk-cli/src/util/render.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Optional } from '../interface/option' -import nunjucks from 'nunjucks' -import fs from 'fs' - -/** - * 渲染 Nunjuncks - * - * @export - * @param {string} template 模板路径 - * @param {string} file 写入文件 - * @param {Optional} content 写入内容 - */ -export function renderTemplate (template: string, file: string, content: Optional): void { - if (fs.existsSync(template)) { - const templateContent = fs.readFileSync(template).toString() - const result = nunjucks.renderString(templateContent, content) - fs.writeFileSync(file, result) - } -} diff --git a/packages/yk-cli/src/util/versionCompare.ts b/packages/yk-cli/src/util/versionCompare.ts deleted file mode 100644 index 4357a656..00000000 --- a/packages/yk-cli/src/util/versionCompare.ts +++ /dev/null @@ -1,51 +0,0 @@ - -import { spawn } from 'child_process' -import fs from 'fs' -import path from 'path' - -/** - * 版本比对 - * - * @export - * @param {("javascript" | "typescript")} type 比对版本的类型 - * @param {string} version 版本号 - * @returns {boolean} 是否一致 - */ -export function versionCompare (type: 'javascript' | 'typescript', version: string): boolean { - const versionFile = path.resolve(__dirname, `../../${type}.version.json`) - const versionDir = path.resolve(__dirname, `../../cache/example/ssr-with-${type === 'javascript' ? 'js' : 'ts'}/package.json`) - if (fs.existsSync(versionFile) && fs.existsSync(versionDir)) { - const oldVersion = require(versionFile).version - return oldVersion === version - } else { - return false - } - -} - -/** - * 记录版本号 - * - * @export - * @param {("javascript" | "typescript")} type 版本类型 - * @param {string} version 版本号 - */ -export function versionlog (type: 'javascript' | 'typescript', version: string): void { - const versionFile = path.resolve(__dirname, `../../${type}.version.json`) - fs.writeFileSync(versionFile, JSON.stringify({ version: version })) -} - -/** - * 移除缓存 - * - * @export - * @param {("javascript" | "typescript")} type - * @returns {Promise} - */ -export async function deletecache (type: 'javascript' | 'typescript'): Promise { - const versionFile = `${type}.version.json` - return new Promise((resolve, reject) => { - const task = spawn(`rm -rf ./cache && rm -rf ./${versionFile}`, [], { cwd: path.resolve(__dirname, '../..'), shell: true }) - task.on('close', (code: number) => { resolve(true) }) - }) -} diff --git a/packages/yk-cli/src/util/versionEffective.ts b/packages/yk-cli/src/util/versionEffective.ts deleted file mode 100644 index 7095fad1..00000000 --- a/packages/yk-cli/src/util/versionEffective.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { config } from './fileconfig' -import { Optional } from '../interface/option' -import { versionCompare, deletecache } from './versionCompare' -import https from 'https' - -/** - * http - * 缓存判断是否有效处理 - * @export - * @param {Optional} option - * @returns {Promise} - */ -export async function getVersionEffective (option: Optional): Promise { - return new Promise((resolve, reject) => { - let url = option.language === 'typescript' ? config.ts_url : config.js_url - let content: string = '' - let packagejson = null - https.get(url, (res) => { - res.on('data', (buffer: Buffer) => { - content = content + buffer.toString() - }) - res.on('error', async (err) => { - console.log('请求版本文件时发生错误', err) - await deletecache(option.language!) - resolve(false) - }) - res.on('end', async () => { - if (content !== '') { - try { - packagejson = JSON.parse(content!) - const version = packagejson.version - const result = versionCompare(option.language!, version) - if (!result) { - await deletecache(option.language!) - } - resolve(result) - } catch (ex) { - await deletecache(option.language!) - resolve(false) - } - } else { - await deletecache(option.language!) - resolve(false) - } - }) - }) - }) -} diff --git a/packages/yk-cli/src/webcomponent.ts b/packages/yk-cli/src/webcomponent.ts deleted file mode 100644 index 37802450..00000000 --- a/packages/yk-cli/src/webcomponent.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Optional } from './interface/option' -import { readFileList } from './util/readFileList' -import { renderTemplate } from './util/render' -import fs from 'fs' -import path from 'path' - -function convert (type: 'sass' | 'css' | 'less'): string { - - if (type === 'sass') { - return 'scss' - } else { - return type - } -} - -/** - * 编译现有组件模板 - * - * @export - * @param {Optional} option - * @returns {Promise} - */ -export async function component (option: Optional): Promise { - return new Promise((resolve, reject) => { - const webpath = path.resolve(__dirname, '../tpl/web') - /** 递归获取web下所有的组件文件模板 */ - const list = readFileList(webpath, []) - list.forEach(p => { - /** 处理所有样式 css/less/scss 模板 */ - if (p.indexOf('.css.nj') > -1) { - let filepath: string | null = null - let filepathPrefix: string = path.resolve(`./${option.appname!}/web/${p.replace(webpath + '/', '').replace('.css.nj', '')}`) - /** js 版本对应的是 *.less */ - if (option.language === 'javascript') { - filepath = filepathPrefix + '.less' - } else if (option.language === 'typescript') { - filepath = filepathPrefix.indexOf('assets') > -1 ? filepathPrefix + '.scss' : filepathPrefix + '.module.scss' - } - /** 把对应的 旧 less / module.scss 文件删除 写入新的 css / scss / less 文件 */ - if (filepath && fs.existsSync(filepath)) { - fs.unlinkSync(filepath) - const newfilepath = `${filepathPrefix}${option.language === 'typescript' && filepath.indexOf('assets') === -1 ? '.module' : ''}.${convert(option.style!)}` - renderTemplate(p, newfilepath, option) - } - } else if (p.indexOf('.js.nj') > -1 && option.language === 'javascript') { - let filepath: string = path.resolve(`./${option.appname!}/web/${p.replace(webpath + '/', '').replace('.js.nj', '.js')}`) - renderTemplate(p, filepath, option) - } else if (p.indexOf('.tsx.nj') > -1 && option.language === 'typescript') { - let filepath: string = path.resolve(`./${option.appname!}/web/${p.replace(webpath + '/', '').replace('.tsx.nj', '.tsx')}`) - renderTemplate(p, filepath, option) - } else if (p.indexOf('.style.d.ts.nj') > -1) { - let filepath: string | null = null - let filepathPrefix: string = path.resolve(`./${option.appname!}/web/${p.replace(webpath + '/', '').replace('.style.d.ts.nj', '')}`) - filepath = filepathPrefix + '.scss.d.ts' - /** 替换less.d.ts || css.d.ts */ - if (filepath && fs.existsSync(filepath)) { - fs.unlinkSync(filepath) - const newfilepath = `${filepathPrefix}.${convert(option.style!)}.d.ts` - renderTemplate(p, newfilepath, option) - } - } - }) - }) -} diff --git a/packages/yk-cli/src/webpackconfig.ts b/packages/yk-cli/src/webpackconfig.ts index 0bfec9e7..9c1268ee 100644 --- a/packages/yk-cli/src/webpackconfig.ts +++ b/packages/yk-cli/src/webpackconfig.ts @@ -1,6 +1,5 @@ +import { resolveApp, renderTemplate } from './util/index' import { Optional } from './interface/option' -import { renderTemplate } from './util/render' -import path from 'path' /** * webpack @@ -9,21 +8,17 @@ import path from 'path' * @param {Optional} option * @returns {Promise} */ -export async function webpack (option: Optional): Promise { - return new Promise((resolve, reject) => { - const filelist = [ - 'tpl/build/paths.js.nj', - 'tpl/build/util.js.nj', - 'tpl/build/webpack.config.base.js.nj', - 'tpl/build/webpack.config.client.js.nj', - 'tpl/build/webpack.config.server.js.nj' - ] - filelist.forEach(p => { - const tplpath = path.resolve(__dirname, '..', p) - const filepath = `./${option.appname}/${p.replace('tpl/', '').replace('.nj', '')}` - renderTemplate(tplpath, filepath, option) - }) - console.log('webpack设置成功.....') - resolve() +export function processWebpack (option: Optional): void { + const fileList = [ + 'tpl/build/paths.js.nj', + 'tpl/build/util.js.nj', + 'tpl/build/webpack.config.base.js.nj', + 'tpl/build/webpack.config.client.js.nj', + 'tpl/build/webpack.config.server.js.nj' + ] + fileList.forEach(file => { + const tplPath = resolveApp(`./${file}`) + const filePath = `./${option.appName}/${file.replace(/tpl|.nj/g, '')}` + renderTemplate(tplPath, filePath, option) }) } diff --git a/packages/yk-cli/tpl/build/webpack.config.base.js.nj b/packages/yk-cli/tpl/build/webpack.config.base.js.nj index 17cebbc4..a4b17cf7 100644 --- a/packages/yk-cli/tpl/build/webpack.config.base.js.nj +++ b/packages/yk-cli/tpl/build/webpack.config.base.js.nj @@ -49,7 +49,6 @@ let webpackModule = { getLocalIdent: getCSSModuleLocalIdent }) }, - {% if style === "less" %} { test: /\.less$/, exclude: /\.module\.less$/, @@ -73,31 +72,6 @@ let webpackModule = { 'less-loader' ) }, - {% elif style === "sass" %} - { - test: /\.scss$/, - exclude: /\.module\.scss$/, - use: getStyleLoaders( - { - importLoaders: 2, - localIdentName: '[local]' - }, - 'sass-loader' - ), - sideEffects: true - }, - { - test: /\.module\.scss$/, - use: getStyleLoaders( - { - importLoaders: 2, - modules: true, - getLocalIdent: getCSSModuleLocalIdent - }, - 'sass-loader' - ) - }, - {% endif %} { exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], loader: require.resolve('file-loader'), diff --git a/packages/yk-cli/tpl/package.json.nj b/packages/yk-cli/tpl/package.json.nj index f1bf0c27..ca477c04 100644 --- a/packages/yk-cli/tpl/package.json.nj +++ b/packages/yk-cli/tpl/package.json.nj @@ -1,6 +1,6 @@ {% if language === "javascript" %} { - "name": "{{appname}}", + "name": "{{appName}}", "version": "1.0.0", "dependencies": { "egg": "^2.21.0", @@ -49,13 +49,8 @@ "css-modules-require-hook": "^4.2.3", "file-loader": "2.0.0", "html-webpack-plugin": "^3.2.0", - {% if style === "less" %} "less": "^3.9.0", "less-loader": "^4.1.0", - {% elif style === "sass" %} - "node-sass": "^4.12.0", - "sass-loader": "^7.1.0", - {% endif %} "mini-css-extract-plugin": "^0.5.0", "optimize-css-assets-webpack-plugin": "5.0.1", "postcss-flexbugs-fixes": "4.1.0", @@ -75,7 +70,7 @@ } {% elif language === "typescript" %} { - "name": "{{appname}}", + "name": "{{appName}}", "version": "1.0.0", "description": "SSR scaffolding using typescript in egg server environment", "egg": { diff --git a/packages/yk-cli/tpl/web/assets/common.css.nj b/packages/yk-cli/tpl/web/assets/common.css.nj deleted file mode 100755 index b78da2a3..00000000 --- a/packages/yk-cli/tpl/web/assets/common.css.nj +++ /dev/null @@ -1,13 +0,0 @@ -* { - margin: 0; - padding: 0; -} - -a { - color: #fff; - text-decoration: none; -} - -ul { - list-style: none; -} \ No newline at end of file diff --git a/packages/yk-cli/tpl/web/layout/index.css.nj b/packages/yk-cli/tpl/web/layout/index.css.nj deleted file mode 100644 index 8a95da09..00000000 --- a/packages/yk-cli/tpl/web/layout/index.css.nj +++ /dev/null @@ -1,22 +0,0 @@ -.normal { - font-family: Georgia, sans-serif; - text-align: center; -} -body { - background-color: #f2f3f5; -} -.title { - position: relative; - display: flex; - align-items: center; - justify-content: center; - height: 55px; - background-color: darkslateblue; - color: #fff; -} -.author { - position: absolute; - font-size: 15px; - bottom: 10px; - right: 100px; -} diff --git a/packages/yk-cli/tpl/web/layout/index.js.nj b/packages/yk-cli/tpl/web/layout/index.js.nj deleted file mode 100644 index 10964a48..00000000 --- a/packages/yk-cli/tpl/web/layout/index.js.nj +++ /dev/null @@ -1,26 +0,0 @@ - -import React from 'react' -{% if style === "less" %} -import '../assets/common.less' -import './index.less' -{% elif style === "sass" %} -import '../assets/common.scss' -import './index.scss' -{% elif style === "css" %} -import '../assets/common.css' -import './index.css' -{% endif %} -import { Link } from 'react-router-dom' - -const Layout = (props) => { - return ( -
-

- Egg + React + SSR -
by ykfe
-

{props.children} -
- ) -} - -export default Layout diff --git a/packages/yk-cli/tpl/web/layout/index.module.style.d.ts.nj b/packages/yk-cli/tpl/web/layout/index.module.style.d.ts.nj deleted file mode 100644 index 0f379dae..00000000 --- a/packages/yk-cli/tpl/web/layout/index.module.style.d.ts.nj +++ /dev/null @@ -1,2 +0,0 @@ -export const title: string; -export const author: string; diff --git a/packages/yk-cli/tpl/web/layout/index.tsx.nj b/packages/yk-cli/tpl/web/layout/index.tsx.nj deleted file mode 100644 index 13b5c885..00000000 --- a/packages/yk-cli/tpl/web/layout/index.tsx.nj +++ /dev/null @@ -1,36 +0,0 @@ -import { Link } from 'react-router-dom'; -import React from 'react'; -{% if style === "sass" %} -import styles from './index.module.scss'; -import '../assets/common.scss'; -{% elif style === "less" %} -import styles from './index.module.less'; -import '../assets/common.less'; -{% elif style === "css" %} -import styles from './index.module.css'; -import '../assets/common.css'; -{% endif %} - - - -/** - * 布局组件 - * - * @export - * @class Layout - * @extends {React.PureComponent} - */ -export class Layout extends React.PureComponent { - - render(): JSX.Element { - return ( -
-

- Egg + React + SSR -
by ykfe
-

- {this.props.children} -
-) - } -} \ No newline at end of file diff --git a/packages/yk-cli/tpl/web/page/index/index.css.nj b/packages/yk-cli/tpl/web/page/index/index.css.nj deleted file mode 100644 index 04f08e63..00000000 --- a/packages/yk-cli/tpl/web/page/index/index.css.nj +++ /dev/null @@ -1,39 +0,0 @@ -{% if style === "css" %} -.list { - background-color: #fff; - width: 1000px; - margin: 100px auto; -} -.list li { - display: flex; - justify-content: space-between; - background-color: #fff; - padding: 20px 30px 20px 80px; - border-bottom: 1px solid #eee; - position: relative; - line-height: 20px; -} -.list li .toDetail a { - font-size: 14px; - color: #888888; -} -{% else %} -.list { - background-color: #fff; - width: 1000px; - margin: 100px auto; - li { - display: flex; - justify-content: space-between; - background-color: #fff; - padding: 20px 30px 20px 80px; - border-bottom: 1px solid #eee; - position: relative; - line-height: 20px; - .toDetail a{ - font-size: 14px; - color: #888 - } - } -} -{% endif %} \ No newline at end of file diff --git a/packages/yk-cli/tpl/web/page/index/index.js.nj b/packages/yk-cli/tpl/web/page/index/index.js.nj deleted file mode 100644 index c36fb059..00000000 --- a/packages/yk-cli/tpl/web/page/index/index.js.nj +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react' -import { Link } from 'react-router-dom' -{% if style === "less" %} -import './index.less' -{% elif style === "sass" %} -import './index.scss' -{% elif style === "css" %} -import './index.css' -{% endif %} - -function Page (props) { - return ( -
-
-
    - { - props.news && props.news.map((item, index) => ( -
  • -
    文章标题: {item.title}
    -
    点击查看详情
    -
  • - )) - } -
-
- ) -} - -Page.getInitialProps = (ctx) => { - return Promise.resolve({ - news: [ - { - id: '1', - title: 'Racket v7.3 Release Notes' - }, - { - id: '2', - title: 'Free Dropbox Accounts Now Only Sync to Three Devices' - }, - { id: '3', - title: 'Voynich Manuscript Decoded by Bristol Academic' - }, - { id: '4', - title: 'Burger King to Deliver Whoppers to LA Drivers Stuck in Traffic' - }, - { id: '5', - title: 'How much do YouTube celebrities charge to advertise your product? ' - } - ] - }) -} -export default Page diff --git a/packages/yk-cli/tpl/web/page/index/index.module.style.d.ts.nj b/packages/yk-cli/tpl/web/page/index/index.module.style.d.ts.nj deleted file mode 100644 index d67d0fa5..00000000 --- a/packages/yk-cli/tpl/web/page/index/index.module.style.d.ts.nj +++ /dev/null @@ -1,2 +0,0 @@ -export const list: string; -export const toDetail: string; diff --git a/packages/yk-cli/tpl/web/page/index/index.tsx.nj b/packages/yk-cli/tpl/web/page/index/index.tsx.nj deleted file mode 100644 index 310384db..00000000 --- a/packages/yk-cli/tpl/web/page/index/index.tsx.nj +++ /dev/null @@ -1,105 +0,0 @@ -import { Startup } from '../../decorator/Startup'; -import { AppRoute } from '../../../config/config.default'; -import { Context } from 'egg'; -import { Link } from 'react-router-dom' -import { Route } from '@/decorator/Route'; -import React from 'react'; -{% if style === "sass" %} -import styles from './index.module.scss'; -{% elif style === "less" %} -import styles from './index.module.less'; -{% elif style === "css" %} -import styles from './index.module.css'; -{% endif %} -import '@/page/news/index'; - -/** - * 当前页面组件 - * 属性类型 - * @interface IPageProps - */ -interface IPageProps { - news: any[]; -} - - -/** - * 实例首页 - * - * @export - * @class Page - * @extends {React.Component} - */ -@Startup() -@Route(AppRoute.index) -export default class Page extends React.Component { - - /** - * 页面初始化取数据方法 - * - * @static - * @param {Context} _ctx 服务端egg 上下文 - * @returns {Promise} - * @memberof Page - */ - static async getInitialProps(_ctx: Context): Promise { - return Promise.resolve({ - news: [ - { - id: '1', - title: 'Racket v7.3 Release Notes' - }, - { - id: '2', - title: 'Free Dropbox Accounts Now Only Sync to Three Devices' - }, - { - id: '3', - title: 'Voynich Manuscript Decoded by Bristol Academic' - }, - { - id: '4', - title: 'Burger King to Deliver Whoppers to LA Drivers Stuck in Traffic' - }, - { - id: '5', - title: 'How much do YouTube celebrities charge to advertise your product? ' - } - ] - }) - } - - constructor(props: IPageProps) { - super(props); - } - - componentDidMount(): void { - - } - - render(): JSX.Element { - return ( -
-
    - { - this.props.news && this.props.news.map((item, index) => ( -
  • -
    文章标题: {item.title}
    -
    - 点击查看详情 -
    -
  • - )) - } -
-
- ); - } -} - - - - - - - diff --git a/packages/yk-cli/tpl/web/page/news/index.css.nj b/packages/yk-cli/tpl/web/page/news/index.css.nj deleted file mode 100644 index d77837fa..00000000 --- a/packages/yk-cli/tpl/web/page/news/index.css.nj +++ /dev/null @@ -1,9 +0,0 @@ -.news-container { - width: 1000px; - background-color: #fff; - margin: 100px auto; - text-align: left; - line-height: 30px; - letter-spacing: 1px; - padding: 10px; -} \ No newline at end of file diff --git a/packages/yk-cli/tpl/web/page/news/index.js.nj b/packages/yk-cli/tpl/web/page/news/index.js.nj deleted file mode 100644 index 16778b03..00000000 --- a/packages/yk-cli/tpl/web/page/news/index.js.nj +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react' -import Layout from './layout' -{% if style === "less" %} -import './index.less' -{% elif style === "sass" %} -import './index.scss' -{% elif style === "css" %} -import './index.css' -{% endif %} - -const mockData = { - '1': `Racket-on-Chez continues to improve. Snapshot builds are currently available at pre.racket-lang.org, and we expect that Racket-on-Chez will be included as a download option in the next release.`, - '2': `This means anyone with more than three devices connected doesn't have to worry right this instant. That will change, however, when it comes time to replace one of your current devices or if you add another device to your collection. At that point, you will have to make a decision.`, - '3': `World's most mysterious text is finally cracked: Bristol academic deciphers lost language of 600-year-old Voynich manuscript to reveal astrological sex tips, herbal remedies and other pagan beliefs`, - '4': `After a successful test in Mexico City, fast-food chain Burger King will begin delivering food to drivers caught in traffic in Los Angeles in what they have dubbed The Traffic Jam Whopper.`, - '5': `Product advertisement and promotion on YouTube is a function of the dedicated audience (or influence) of the individual (influencer) anchoring the advertising or promotion.` -} - -function News (props) { - return ( -
- 文章详情: {props.newsDetail} -
- ) -} - -// 自定义Layout -News.Layout = Layout - -News.getInitialProps = (ctx) => { - const newsId = __isBrowser__ ? ctx.match.params.id : ctx.params.id - return Promise.resolve({ - newsDetail: mockData[newsId] - }) -} - -export default News diff --git a/packages/yk-cli/tpl/web/page/news/index.module.scss.d.ts.nj b/packages/yk-cli/tpl/web/page/news/index.module.scss.d.ts.nj deleted file mode 100644 index cb0ff5c3..00000000 --- a/packages/yk-cli/tpl/web/page/news/index.module.scss.d.ts.nj +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/packages/yk-cli/tpl/web/page/news/index.tsx.nj b/packages/yk-cli/tpl/web/page/news/index.tsx.nj deleted file mode 100644 index 5fc0c9d2..00000000 --- a/packages/yk-cli/tpl/web/page/news/index.tsx.nj +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react'; -import { Context } from 'egg'; -import { AppRoute } from '../../../config/config.default'; -import { Route } from '@/decorator/Route'; -{% if style === "sass" %} -import styles from './index.module.scss'; -{% elif style === "less" %} -import styles from './index.module.less'; -{% elif style === "css" %} -import styles from './index.module.css'; -{% endif %} - -/** - * 当前页面 - * 属性类型 - * @interface INewsProps - */ -interface INewsProps { - - /** - * 当前条目详情信息 - * - * @type {string} - * @memberof INewsProps - */ - newsDetail: string; -} - -/** - * 实例-详情组件 - * - * @export - * @class News - * @extends {React.Component} - */ -@Route(AppRoute.news) -export default class News extends React.Component { - - /** - * 页面初始化取数据方法 - * - * @static - * @param {Context} ctx 服务端egg 上下文 - * @returns {Promise} - * @memberof News - */ - static async getInitialProps(ctx: Context): Promise { - const mockData = { - '1': `Racket-on-Chez continues to improve. Snapshot builds are currently available at pre.racket-lang.org, and we expect that Racket-on-Chez will be included as a download option in the next release.`, - '2': `This means anyone with more than three devices connected doesn't have to worry right this instant. That will change, however, when it comes time to replace one of your current devices or if you add another device to your collection. At that point, you will have to make a decision.`, - '3': `World's most mysterious text is finally cracked: Bristol academic deciphers lost language of 600-year-old Voynich manuscript to reveal astrological sex tips, herbal remedies and other pagan beliefs`, - '4': `After a successful test in Mexico City, fast-food chain Burger King will begin delivering food to drivers caught in traffic in Los Angeles in what they have dubbed The Traffic Jam Whopper.`, - '5': `Product advertisement and promotion on YouTube is a function of the dedicated audience (or influence) of the individual (influencer) anchoring the advertising or promotion.` - } - const newsId = __isBrowser__ ? ctx.match.params.id : ctx.params.id - return Promise.resolve({ - newsDetail: mockData[newsId] - }) - } - - componentDidMount() { - - } - - - render(): JSX.Element { - return ( -
- 文章详情: {this.props.newsDetail} -
- ) - } -} \ No newline at end of file diff --git a/packages/yk-cli/tpl/web/page/news/layout.css.nj b/packages/yk-cli/tpl/web/page/news/layout.css.nj deleted file mode 100644 index bb423e66..00000000 --- a/packages/yk-cli/tpl/web/page/news/layout.css.nj +++ /dev/null @@ -1,22 +0,0 @@ -.normal { - font-family: Georgia, sans-serif; - text-align: center; -} -body { - background-color: #f2f3f5; -} -.title { - position: relative; - display: flex; - align-items: center; - justify-content: center; - height: 55px; - background-color: darkslateblue; - color: #fff; -} -.author { - position: absolute; - font-size: 15px; - bottom: 10px; - right: 100px; -} diff --git a/packages/yk-cli/tpl/web/page/news/layout.js.nj b/packages/yk-cli/tpl/web/page/news/layout.js.nj deleted file mode 100644 index 71304596..00000000 --- a/packages/yk-cli/tpl/web/page/news/layout.js.nj +++ /dev/null @@ -1,20 +0,0 @@ - -import React from 'react' -{% if style === "less" %} -import './layout.less' -import '@/assets/common.less' -{% elif style === "sass" %} -import './layout.scss' -import '@/assets/common.scss' -{% elif style === "css" %} -import './layout.css' -import '@/assets/common.css' -{% endif %} -import { Link } from 'react-router-dom' - -const Layout = (props) => { - return ( -

News Page
by ykfe

{props.children}
) -} - -export default Layout diff --git a/packages/yk-cli/types/check.d.ts b/packages/yk-cli/types/check.d.ts new file mode 100644 index 00000000..f7af1ecb --- /dev/null +++ b/packages/yk-cli/types/check.d.ts @@ -0,0 +1,9 @@ +import { Optional } from './interface/option'; +/** + * 应用初始化函数 + * + * @export + * @param {Optional} option 应用全局配置 + * @returns {Promise} + */ +export declare function checkRepeat(option: Optional): Promise; diff --git a/packages/yk-cli/types/config.d.ts b/packages/yk-cli/types/config.d.ts index d82a0e10..9abbeac0 100644 --- a/packages/yk-cli/types/config.d.ts +++ b/packages/yk-cli/types/config.d.ts @@ -6,4 +6,4 @@ import { Optional } from './interface/option'; * @param {Optional} option * @returns {Promise} */ -export declare function appconfig(option: Optional): Promise; +export declare function getConfig(option: Optional): Promise; diff --git a/packages/yk-cli/types/interface/answers.d.ts b/packages/yk-cli/types/interface/answers.d.ts new file mode 100644 index 00000000..454ce941 --- /dev/null +++ b/packages/yk-cli/types/interface/answers.d.ts @@ -0,0 +1,10 @@ +export interface Answers { + /** 应用名称 */ + appName?: string; + /** 样式预处理 */ + style?: 'less' | 'sass' | 'css'; + /** 状态管理的中间件 */ + store?: string; + /** 项目语言 */ + language?: 'typescript' | 'javascript'; +} diff --git a/packages/yk-cli/types/interface/option.d.ts b/packages/yk-cli/types/interface/option.d.ts index 4484aac6..963ae78d 100644 --- a/packages/yk-cli/types/interface/option.d.ts +++ b/packages/yk-cli/types/interface/option.d.ts @@ -6,7 +6,7 @@ export interface Optional { /** 包管理工具 */ tool?: string; /** 应用名称 */ - appname?: string; + appName?: string; /** 样式预处理 */ style?: 'less' | 'sass' | 'css'; /** 状态管理的中间件 */ diff --git a/packages/yk-cli/types/package.d.ts b/packages/yk-cli/types/package.d.ts index 116f52ea..91ecc95f 100644 --- a/packages/yk-cli/types/package.d.ts +++ b/packages/yk-cli/types/package.d.ts @@ -6,4 +6,4 @@ import { Optional } from './interface/option'; * @param {Optional} option 应用全局配置 * @returns {Promise} */ -export declare function packagejson(option: Optional): Promise; +export declare function processPackage(option: Optional): Promise; diff --git a/packages/yk-cli/types/update.d.ts b/packages/yk-cli/types/update.d.ts index cca62412..cb3703fd 100644 --- a/packages/yk-cli/types/update.d.ts +++ b/packages/yk-cli/types/update.d.ts @@ -1,4 +1,3 @@ -import { Optional } from './interface/option'; /** * 判断NPM包自动更新 * @@ -6,4 +5,4 @@ import { Optional } from './interface/option'; * @param {Optional} option 全局应用配置 * @returns {Promise} */ -export declare function updatelocal(option: Optional): Promise; +export declare function update(): Promise; diff --git a/packages/yk-cli/types/util/fileconfig.d.ts b/packages/yk-cli/types/util/fileconfig.d.ts deleted file mode 100644 index 6462d0b6..00000000 --- a/packages/yk-cli/types/util/fileconfig.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * 脚手架参数 - */ -export declare const config: { - ts_url: string; - js_url: string; - branch: string; -}; diff --git a/packages/yk-cli/types/util/index.d.ts b/packages/yk-cli/types/util/index.d.ts new file mode 100644 index 00000000..befcd1bb --- /dev/null +++ b/packages/yk-cli/types/util/index.d.ts @@ -0,0 +1,25 @@ +/// +import { exec } from 'child_process'; +import { Optional } from '../interface/option'; +export declare const processError: (err: string) => void; +export declare const execPromise: typeof exec.__promisify__; +export declare const downloadPromise: Function; +export declare const resolveApp: (source: string) => string; +export declare const getPromise: object; +/** + * http + * 缓存判断是否有效处理 + * @export + * @param {Optional} option + * @returns {Promise} + */ +export declare function getVersionEffective(option: Optional): Promise; +/** + * 渲染 Nunjuncks + * + * @export + * @param {string} template 模板路径 + * @param {string} file 写入文件 + * @param {Optional} content 写入内容 + */ +export declare function renderTemplate(template: string, file: string, content: Optional): void; diff --git a/packages/yk-cli/types/util/readFileList.d.ts b/packages/yk-cli/types/util/readFileList.d.ts index 19ad2028..e651ab28 100644 --- a/packages/yk-cli/types/util/readFileList.d.ts +++ b/packages/yk-cli/types/util/readFileList.d.ts @@ -7,4 +7,4 @@ * @param {(string | null)} [ext=null] 后缀过滤 * @returns */ -export declare function readFileList(dir: string, filesList?: string[], ext?: string | null): string[]; +export declare function readFileList(dir: string, ext?: string | null): string[]; diff --git a/packages/yk-cli/types/util/versionEffective.d.ts b/packages/yk-cli/types/util/versionEffective.d.ts index c1d558c6..e69de29b 100644 --- a/packages/yk-cli/types/util/versionEffective.d.ts +++ b/packages/yk-cli/types/util/versionEffective.d.ts @@ -1,9 +0,0 @@ -import { Optional } from '../interface/option'; -/** - * http - * 缓存判断是否有效处理 - * @export - * @param {Optional} option - * @returns {Promise} - */ -export declare function getVersionEffective(option: Optional): Promise; diff --git a/packages/yk-cli/types/webpackconfig.d.ts b/packages/yk-cli/types/webpackconfig.d.ts index 664f6c5b..c7b4562c 100644 --- a/packages/yk-cli/types/webpackconfig.d.ts +++ b/packages/yk-cli/types/webpackconfig.d.ts @@ -6,4 +6,4 @@ import { Optional } from './interface/option'; * @param {Optional} option * @returns {Promise} */ -export declare function webpack(option: Optional): Promise; +export declare function processWebpack(option: Optional): Promise;