手写一个cli笔记步骤
创建项目目录文件
初始化项目
npm init生成package.json- 在package.json中
"bin": {
"zmp": "./bin/zmp.js"
},
- 先安装一些依赖吧
npm install @babel/core @babel/preset-env @babel/preset-react babel-loader commander fs-extra git-promise html-webpack-plugin inquirer nanospinner webpack webpack-chain webpack-cli webpack-dev-server axios --save
- 命令行执行
npm link把指令链接起来
在项目目录下新建文件夹bin
- 在
bin文件夹下新建zmp.js文件
// zmp.js文件
#!/usr/bin/env node
// console.log('zmp------')
const pkg = require('../package.json')
// 新版本的写法
const { Command } = require('commander');
const program = new Command();
const cli = require('../cli')
// 设置当前脚手架版本号
program.version(pkg.version, '-v,--version')
.usage('<command> [options]');
program.command('init')
.description('创建项目')
.option('-t,--template [template]','JSON数据 HTTP的地址或者是文件的相对或绝对路径')
.action(options => {
// console.log('init', options)
cli.exec('init', options)
})
program.command('dev')
.description('启动开发服务器')
.option('-t,--template [template]','JSON数据 HTTP的地址或者是文件的相对或绝对路径')
.action(options => {
// console.log('init', options)
cli.exec('dev', options)
})
program.parse(process.argv);
在项目目录下新建文件夹cli
index.js
class ZMPScript {
async exec(name,options) {
await require(`./${name}`).setup(options)
}
}
module.exports = new ZMPScript()
init.js下载git仓库的逻辑代码
const axios = require('axios')
const { createSpinner } = require('nanospinner')
const git = require('git-promise')
const fs = require('fs-extra')
const path = require('path')
class Init {
templates = {}
async checkTemplate(url) {
const {
data
} = await axios.get(url)
return data
}
async setup(options) {
if (typeof options.template === 'string') {
const templates = await this.checkTemplate(options.template);
if (templates) {
this.templates = templates
}
}
await this.selectTemplate(this.templates)
}
async selectTemplate(templates) {
console.log('this====templates', this.templates)
const inquirer = await (await import('inquirer')).default
const answers = await inquirer.prompt([
{
type: 'input',
name: 'name',
message: '请输入项目名称',
default: function() {
return 'zmp-project'
}
},
{
type:'list',
name: 'template',
message: '请选择模版',
choices: Object.keys(templates)
}
])
// console.log('answer', answers)
const gitRepo = this.templates[answers.template]
await this.downloadRepo(gitRepo,answers.name)
}
async downloadRepo(repoPath,localPath) {
const spinner = createSpinner().start()
spinner.start({text:'downloading\n'})
// 下载代码
await git(`clone ${repoPath} ${localPath}`)
spinner.success({
text: `cd ${localPath} & npm install &npm run dev`
})
}
}
module.exports = new Init()
dev.js启动服务器的逻辑代码
const WebpackDevServer = require('webpack-dev-server')
const webpack = require('webpack')
const {getConfig} = require('../config')
class DevServer {
async setup() {
await this.startServer()
}
async startServer() {
// const config = {devServer: {port: 1008}}
// const config = {devServer: {}}
const config = getConfig()
const compiler = webpack(config)
this.server = new WebpackDevServer(config.devServer,compiler)
this.server.start()
}
}
module.exports = new DevServer()
在项目目录下新建文件夹config,用来分析项目中的传入配置
index.js
const path = require('path')
const webpack = require('webpack')
const WebpackChain = require('webpack-chain')
const HtmlWebpackPlugin = require('html-webpack-plugin')
function processDefault(empConfig) {
const devServer = empConfig.server || {}
delete empConfig.server
const mfOptions = {// 创建模块联邦选项对象
filename: 'emp.js',// 当前容器为了对外提供模块联邦的服务,生成的单独的文件名
...empConfig.empShare
}
delete empConfig.empShare
return {
context: process.cwd(),
mode: 'development',
devtool: false,
devServer,
plugin: {
html: {
plugin: HtmlWebpackPlugin,
args: [
{
template: path.join(__dirname, '../template/index.html')
}
]
},
mf: {
plugin: webpack.container.ModuleFederationPlugin,
args: [mfOptions]
}
},
module: {
rule: {
compile: {
test: /\.js$/,
exclude: [/node_modules/],
use: {
'babel-loader': {
loader: require.resolve('babel-loader'),
options: {
presets: [
require.resolve('@babel/preset-env'),
require.resolve('@babel/preset-react')
]
}
}
}
}
}
},
...empConfig
}
}
exports.getConfig = () => {
const Config = new WebpackChain()
const empConfigPath = path.resolve(process.cwd(), 'emp-config.js')
const empConfig = require(empConfigPath)
const afterConfig = processDefault(empConfig)
Config.merge(afterConfig)
console.log('config.toconfig',Config.toConfig())
return Config.toConfig()
}
测试
zmp init -t https://static.zhufengpeixun.com/template_1680930323773.json
zmp dev