背景
vscode的代码片段可以通过预置的代码模板快速生成一段代码,那么如果通过预置好的项目模板快速生成项目,代码片段就处理不了了。但是利用自定义插件功能可以做到。
抽离模板
保留一些固定的文件和代码,抽离出最基本的代码结构。在代码模板中,和包名一样的变量我们可以用【packageName】、【PackageName】一些特殊的字符来进行占位,后续在快速生产模板时,可以利用正则的方式来进行替换。
├── template
| ├── api
| | ├── index.ts
| | ├── service.ts
| ├── index.html
| ├── main.ts
| ├── config.json
| ├── App.vue
| ├── store
| | ├── index.ts
最后将代码模板拷贝到插件工程中,我们接下来就可以编写插件的新建模板功能了。
新建模板
说是新建模板,其实就是将预置的模板拷贝到指定目录,拷贝的过程中替换上一步定义占位符即可。
定义copy文件的方法
const path = require('path')
const fs = require('fs')
const stream = require('stream')
const vscode = require('vscode')
/**
* 复制文件夹到目标文件夹
* @param {string} src 源目录
* @param {string} dest 目标目录
* @param {function} callback 回调
*/
const copyDir = (src, dest, callback) => {
const packageName = dest.split('/').pop()
const copy = (copySrc, copyDest) => {
fs.readdir(copySrc, (err, list) => {
if (err) {
callback(err)
return
} else {
list.forEach(item => {
const ss = path.resolve(copySrc, item)
fs.stat(ss, (err, stat) => {
if (err) {
callback(err)
} else {
const curSrc = path.resolve(copySrc, item)
const curDest = path.resolve(copyDest, item)
if (stat.isFile()) {
// 文件,直接复制
const writer = fs.createWriteStream(curDest)
const reader = fs.createReadStream(curSrc)
// 替换占位符
const transform = stream.Transform({
highWaterMark: 2,
transform: function (buf, enc, next) {
const upperChunk = buf
.toString()
.replaceAll('[packageName]', packageName)
.replaceAll(
'[PackageName]',
packageName[0].toUpperCase() + packageName.substr(1)
)
next(null, upperChunk)
}
})
reader.pipe(transform).pipe(writer)
} else if (stat.isDirectory()) {
// 目录,进行递归
fs.mkdirSync(curDest, { recursive: true })
copy(curSrc, curDest)
}
}
})
})
}
})
}
fs.access(dest, err => {
if (err) {
// 若目标目录不存在,则创建
fs.mkdirSync(dest, { recursive: true })
} else {
vscode.window.showErrorMessage('该目录已存在!')
return
}
copy(src, dest)
})
}
module.exports = copyDir
利用了node的stream流,来对内容进行处理。
插件部分代码:
context.subscriptions.push(
vscode.commands.registerCommand('demo.createPackage', async uri => {
const packageName = await vscode.window.showInputBox({
prompt: '输入项目名称',
validateInput: input => {
if (input.length > 0 && /^[a-zA-Z0-9]+$/.test(input)) {
return ''
} else {
return '输入有效名称'
}
}
})
if (!packageName) {
return
}
copyDir(path.resolve(__dirname, './template'), uri.path.slice(1) + '/' + packageName)
})
)
效果展示
在文件目录右键选择新建项目,输入项目名称后,自动生产对应目录,并且代码中占位符地方也替换成输入的名称。