前段脚手架搭建
快速🔜
- 1 查看当前环境下是否已经安装成功脚手架
执行
start
命令 如果成功会有提示 否则找不到
正文
从零搭建属于自己的脚手架到发布
初始化项目
1 创建一个文件夹 然后npm init -y 初始化
2 创建一个index.js文件,然后修改package.json文件
index.js
// 告诉npm 如何执行下面的脚本命令 简单理解为node执行脚本
#!/usr/bin/env node
- package.json
// bin 项用来指定各个内部命令对应的可执行文件的位置。
"bin":{
"start":"./index.js"
}
安装上面需要的依赖插件 [具体使用 点击上面的链接自行查看]
- commander
编写代码来描述你的命令行界面
- glob
用来匹配文件,可以查看当前目录下的文件
- download-git-repo
主要是为了下载你所需要的git项目
- chalk@4.0.0 [这个版本,主要是为了支持require引入,而不是使用es6]
可以修改文字颜色
- metalsmith
可以读取和写入文件
- handlebars
可以构建模版
- lodash
快速的对js进行一些处理的工具库
- cross-spawn
主要是对跨平台命令的处理
- ora@5.0.0[这个版本,主要是为了支持require引入,而不是使用es6]
一个loading库
- inquirer@6.0.0[这个版本,主要是为了支持require引入,而不是使用es6]
可以提供命令行查询对命令操作进行选择性的交互处理
源码package.json
{
"name": "template-cli",
"version": "1.0.6",
"description": "",
"main": "index.js",
"bin": {
"start": "./index.js"
},
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": ["template","react","antd"],
"author": "kingcwt",
"license": "ISC",
"dependencies": {
"chalk": "4.0.0",
"commander": "^9.4.0",
"cross-spawn": "^7.0.3",
"download-git-repo": "^3.0.2",
"glob": "^8.0.3",
"handlebars": "^4.7.7",
"inquirer": "6.0.0",
"lodash": "^4.17.21",
"metalsmith": "^2.5.0",
"ora": "^5.0.0"
}
}
源码index.js
#!/usr/bin/env node
const { Command } = require('commander');
const { promisify } = require('util')
const program = new Command();
const path = require('path');
const glob = require('glob'); // npm i glob -D
const download = promisify(require('download-git-repo'))
const chalk = require("chalk");
const generator = require('./lib/generator');
const inquirer = require('inquirer');
const ora = require('ora');
const install = require('./lib/install.js');
program
.name('Project template')
.description('项目模版')
.version('0.0.1');
program
.command('create') // 输入create 命令【必填】
.argument('<project-name>') // 随意输入的参数 这里指输入的项目名称
.description('创建模版名称')
.action( async (projectName)=>{
if (!projectName) program.help();
const list = glob.sync('*');
let isExist = list.includes(projectName);
if(isExist){
const name = chalk.hex('afcb92').bold(projectName)
return console.log(`🍠 ${name} folder already exists.`)
}
// 选择安装方式
inquirer.prompt([
{
name:"package",
type: 'list',
choices:['yarn','tyarn','cnpm','npm','npx'],
message:'select the package management'
}
]).then(async(answer)=>{
// 1. 下载模版
const colorProjectName = chalk.hex('afcb92').bold(`~/${projectName}`);
console.log(`Createing a new react app in ${colorProjectName}`)
let loading = ora('🚗 开始下载模版...').start()
// 远程模版地址,默认master分支,这里下载的是main分支
const repoUrl = 'direct:https://github.com/[你的github用户名称]/[仓库名称].git#[分支]'
await download(repoUrl, projectName, { clone: true });
const preConsole = chalk.cyan('cd ')+projectName;
const nextConsole = chalk.cyan(`yarn dev`);
const currentProjectName = chalk.hex('afcb92').bold(projectName);
loading.stop();
loading.succeed('下载模版成功')
// 渲染模版
generator({projectName},path.resolve(__dirname,'./template'),`./${projectName}`)
console.log(chalk.green('Project initialization finished!'))
console.log(chalk.yellowBright('start install dependencies...'))
// 安装依赖
await install({
cwd: path.join(process.cwd(), projectName),
package: answer.package,
}).then(() => {
console.log(`${preConsole}\r\n${nextConsole}`)
})
.catch((error)=>{
loading.fail(error);
})
})
return;
})
program.parse();
源码lib/generator.js
// 对模板处理
const Metalsmith = require('metalsmith')
const Handlebars = require('handlebars')
const rm = require('rimraf').sync
const chalk = require('chalk')
const _ = require('lodash')
module.exports = function(metadata = {}, source, destination = '.') {
if (!source) {
return Promise.reject(new Error(`无效的source:${source}`))
}
return new Promise((resolve, reject) => {
Metalsmith(process.cwd())
.metadata(metadata) //metadata 为用户输入的内容
.clean(false)
.source(source) //模板文件 path
.destination(destination) //最终编译好的文件存放位置
.use((files, metalsmith, done) => {
Object.keys(files).forEach(fileName => { //遍历替换模板
if (!_.startsWith(fileName, 'src/font')) { //判断是否为字体文件,字体文件不用替换
const fileContentsString = files[fileName].contents.toString() //Handlebar compile 前需要转换为字符创
files[fileName].contents = Buffer.from(Handlebars.compile(fileContentsString)(metalsmith.metadata()))
}
})
done()
}).build(err => { // build
rm('source') //删除下载下来的模板文件,‘source’是路径
if (err) {
console.log(chalk.red(`Metalsmith build error: ${err}`))
return reject(err)
} else {
return resolve()
}
})
})
}
源码lib/install.js
// 下载封装
const spawn = require('cross-spawn');
module.exports = function(options){
const cwd = options.cwd;
return new Promise((resolve,reject)=>{
const command = options.package;
const args = ['install','--save','--save-exact', '--loglevel', 'error'];
const child = spawn(command, args, {
cwd,
stdio: ['pipe', process.stdout, process.stderr],
})
child.once('close', (code) => {
if (code !== 0) {
reject({
command: `${command} ${args.join(' ')}`,
})
return
}
resolve()
})
child.once('error', reject)
})
}
源码template/package.json
// 从github下来的模版项目对应的package.json的替换 这里只处理了一下名称 其他的可以自行处理
{
"name": "{{projectName}}",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "npm run build:less && vite --host",
"xxx":...
},
"lint-staged": {
"**/*.ts?(x)": [
"prettier --write ./src",
"eslint ./src"
]
},
"dependencies": {
"xlsx": "^0.18.5"
"xxx":...
},
"devDependencies": {
"vitest": "^0.9.3"
"xxx":...
}
}
本地运行测试
上面文件内容库等都弄好以后 接下来就是运行测试
1 在当前项目下执行 npm link
建立软链接
2 这个时候就可以执行package.json下的bin字段下你自己输入的命令,我这里是start,所以执行 start create [输入的项目名称]
3 如果你发布以后 需要测试在本地是不是能用 这个时候需要解除软链接 执行npm uninstall -g [当前的项目名称]
,我这里执行npm uninstall -g template-cli
,执行完以后发现start命令找不到就是ok啦
发布
这里简单介绍一下
1 你要发布到npm源 你需要先切换成npm的源 执行npm get registry
查看当前链接的源是哪个
2 设置成npm源 npm set registry [对应源的链接]
,可以安装一个nrm 然后执行nrm ls
可以查看你当前环境的所有源 然后设置一下就行
3 在当前项目下执行npm publish
发布 然后就可以在npm上看到你的包了 这里你要提交注册一个npm账户哦 具体如何注册就不说了
4 执行npm unpublish [包名] --force
可以删除对应源上面的包 --force 是强制的意思 发布的命令如果失败 也可以加上 --force哦
到这里就结束了 ~ 🚗
会用到的命令
- 查看全局npm配置命令
npm ls --global --depth 0
- 解除软连接
npm unlink
- 强制建立软连接
npm link --force
- 查看npm源
npm config get registry
- 设置npm源
npm config set registry [链接]
- 发布到npm
npm publish
- 删除npm上的包
npm unpublish [包名] --force
- npm查看全局的包
npm list -g
- 删除全局下的某个npm包
npm uninstall -g [包名]
- nrm ls
查看当前环境下可用的源
使用的库
- commander
https://github.com/tj/commander.js/blob/HEAD/Readme_zh-CN.md
- glob
https://github.com/isaacs/node-glob
- cfonts
https://github.com/dominikwilkowski/cfonts
- download-git-repo
https://gitlab.com/flippidippi/download-git-repo
- chalk@4.0.0
https://github.com/chalk/chalk
- metalsmith
https://github.com/metalsmith/metalsmith
- handlebars
https://github.com/handlebars-lang/handlebars.js
- lodash
https://github.com/lodash/lodash
- cross-spawn
https://github.com/moxystudio/node-cross-spawn
- ora@5.0.0
https://github.com/sindresorhus/ora
- inquirer@6.0.0
https://github.com/SBoudrias/Inquirer.js