### 目录结构
|-- ProjectFolder
|-- .gitignore
|-- .npmrc
|-- package.json
|-- qz-init.js
|-- README.md
|-- lib
| |-- helper.js
| |-- update-check.js
|-- templates
|-- xxxx
### 插件
* [`ejs`](https://www.npmjs.com/package/ejs) 模板插入
* [`prompts`](https://www.npmjs.com/package/prompts) 命令行问答式窗口
* [`update-check`](https://www.npmjs.com/package/update-check) 检查插件是否有更新
### 整体思路
将不同的模板文件放到`templates`目录下,通过命令行问答的方式,选择不同的类型,进而下载对应的模板;
### `package.json`
配置`bin:{"cli":"./qz-init.js"}`
### `init.js`
```js
#! /usr/bin/env node
const path = require('path')
const fs = require('fs')
const prompts = require('prompts')
const ejs = require('ejs')
const chalk = require('chalk')
const updateCheck = require('./lib/update-check')
const pkg = require('./package')
const helpers = require('./lib/helper')
// Prepare container for response data
const responses = {
update: false,
mode: '',
npmName: '',
language: '',
savePath: '',
}
// Create function to display update notification at script completion
function displayUpdateMessage() {
/* eslint-disable no-console */
if (responses.update) {
const {latest} = responses.update
if (latest)
console.log(
`\r\n${chalk.black.bgGreen(' UPDATE AVAILABLE ')}${chalk.red(
'-->'
)} The latest version of ${pkg.name} is ${chalk.yellow(latest)}\r\n`
)
}
/* eslint-enable no-console */
}
// Create cancel function to exit the process
function onCancel() {
// eslint-disable-next-line no-console
console.log('User canceled. Goodbye!')
displayUpdateMessage()
process.exit()
}
// Create async prompt functions
async function checkForUpdates() {
let update = null
try {
update = await updateCheck(pkg)
} catch (err) {
const errIntro = ` ${pkg.name} failed to check for updates `
// eslint-disable-next-line no-console
console.error(
`\r\n${chalk.black.bgRed(errIntro)}${chalk.red('-->')} ${err}\r\n`
)
update = null
}
if (update) {
responses.update = update
}
}
async function getMode() {
const question = {
type: 'select',
name: 'mode',
message: 'Is this a canoe application?',
choices: [{title: 'Canoe Application', value: 'canoe'}],
initial: 0,
}
const response = await prompts(question, {onCancel})
responses.mode = response.mode
}
async function getName() {
const {mode} = responses
let tmpKebabName = ''
const questions = [
{
type: 'text',
name: 'npmName',
message: `What is the npm name of your ${mode}?`,
validate(val) {
const kebabName = helpers.kebabcase(val).trim()
return kebabName !== ''
},
},
]
const response = await prompts(questions, {
onSubmit(prompt, answer) {
if (prompt.name === 'npmName')
tmpKebabName = helpers.kebabcase(answer).trim()
},
onCancel,
})
responses.npmName = response.npmName
responses.savePath = `./${tmpKebabName}`
}
async function getLanguage() {
const {mode} = responses
const question = {
type: 'select',
name: 'language',
message: `Will this ${mode} be written in JavaScript or TypeScript?`,
choices: [
// {title: 'JavaScript', value: 'js'},
{title: 'TypeScript', value: 'ts'},
],
initial: 0,
}
const response = await prompts(question, {onCancel})
responses.language = response.language
}
async function getSavePath() {
const {mode, savePath} = responses
const questions = [
{
type: 'text',
name: 'savePath',
message: `Enter a location to save the ${mode} files:`,
initial() {
return savePath
},
validate: (val) => {
// Validate path does not exist, then create directory
const pathExists = fs.existsSync(val)
return !pathExists
},
},
]
const response = await prompts(questions, {
onCancel,
})
responses.savePath = path.resolve(response.savePath)
return response
}
let template_files = []
function findAllFiles(srcPath) {
let paths = fs.readdirSync(srcPath)
paths.forEach((pathItem) => {
if (pathItem === 'node_modules') return
if (pathItem === 'package.json') return
let fullPath = path.join(srcPath, pathItem)
let stat = fs.statSync(fullPath)
if (stat.isFile()) {
template_files.push(fullPath)
} else if (stat.isDirectory()) {
findAllFiles(fullPath)
}
})
}
// Create function to scaffold based on response data
function scaffold(data) {
// Stop prompting for input, start processing
const vars = {
npmName: data.npmName,
ts: data.language === 'ts',
}
let srcPath = path.join.apply(null, [
__dirname,
'templates',
data.mode === 'canoe' ? 'canoe' : '',
])
let destPath = path.join.apply(null, [data.savePath])
findAllFiles(srcPath)
template_files.forEach((filePath) => {
let relative_path = filePath.replace(srcPath, '')
let target_absolute_path = path.join(destPath, relative_path)
helpers.ensureDirectoryExists(target_absolute_path)
if (filePath.indexOf('demo-package.json') > -1) {
fs.writeFileSync(
target_absolute_path.replace('demo-package.json', 'package.json'),
ejs.render(fs.readFileSync(filePath).toString(), vars)
)
} else {
fs.writeFileSync(target_absolute_path)
}
})
// Display completion messages
let completeMessage
if (data.mode === 'canoe') {
completeMessage = `
Init is complete, your files have been generated and saved into the directory you specified above.
When you're ready, run \`yarn install && yarn run serve\` to start your application.`
}
// eslint-disable-next-line no-console
console.log(completeMessage)
}
let args = process.argv.slice(2)
if (args[0] === '-v' || args[0] === '--version') {
console.log(`v${pkg.version}`)
} else if (args[0] === '-h' || args[0] === '--help') {
console.log(' usage:\n')
console.log(' -v --version [show version]')
} else {
// Begin asking for input, then scaffold
checkForUpdates()
.then(displayUpdateMessage)
.then(getMode)
.then(getName)
.then(getLanguage)
.then(getSavePath)
.then(() => {
scaffold(responses)
displayUpdateMessage()
})
}
```
- 前端
- C1-Javascript
- H5图片分块和断点续传
- JavascriptPatterns[Stoyanstefanov]
- macotask和microtask
- 前端代码生成器
- 跨域
- 页面回到顶部滚动按钮实现
- C2-CSS
- 浏览器的一些单位
- 盒模型
- 移动端判断横竖屏
- C3-框架
- ReactNative
- 开发环境搭建(安卓篇)
- Vue
- vue+pdfjs使用
- vue+typescript使用实践
- vue+webpack3.x集成typescript
- Vue源码3
- vue源码分析1
- vue源码分析2
- vue笔记
- C4-工具
- git
- Gitlab-CICD
- mock规则
- vscode-settings
- webpack自定义命令,切换代理地址
- 正则表达式
- 深入浅出webpack
- C5-Node
- express
- express源码阅读
- nightmare使用指南
- 爬虫1.0
- C6-微信
- 微信
- C7-Canvas
- 基础API
- 前端随笔笔记
- 后端
- C1-Java
- shiro
- C2-Linux
- ffmpeg
- ITerm
- Linux
- MongoDB安装
- MySql安装
- Ngnix反向代理
- 常见错误
- 备忘
- mac
- 备忘-Work
- 备忘Link
- 服务器资源
- 教程
- Hexo个人博客搭建笔录
- 文档
- CSS编码规范
- 前端编码规范
- 随笔
- 整理
- 正则
- 链接收藏
- 面试
- CodeWars题库
- CodeWars题库(二)
- Java社招面试题
- Java面试
- Web面试
- 前端笔试题
- 笔试题