TypeScript开发环境搭建(VSCode+NodeJs)自动创建
TypeScript开发环境搭建(VSCode+NodeJs)自动创建
如果只是使用VS Code + Node.js来编写TypeScript代码,可能需要以下的命令:
npm init -y
npm install typescript --save-dev
npm install @types/node --save-dev
npx tsc --init --rootDir src --outDir lib --esModuleInterop --resolveJsonModule --lib es6,dom --module commonjs
npm install --save-dev ts-node
npm install --save-dev nodemon
并像下面这样配置package.json文件,才能完成开发环境的搭建。
"scripts": {
"start": "npm run build:live",
"build": "tsc -p .",
"build:live": "nodemon --watch src/**/*.ts --exec ts-node src/index.ts",
"all": "start & build"
},
每次都做这些配置就是是不是很麻烦?那么怎么解决?编写Node.js CLI程序,这样每次创建同样的目录结构和文件时,只需要在命令行输入命令即可。
创建Node.js CLI
-
新建文件夹mycli。
-
在新建的文件夹下打开命令行,执行命令npm init -y以创建package.json文件。按以下方式配置bin字段。配置后才能在控制台使用自己创建的命令。
"bin": {
"mycli": "./index.js"
}
- 在当前目录(即mycli)下创建index.js文件。这是命令要执行的文件。
- 在文件首行写“#!Node”,表示使用node来执行该文件。(Windows系统)
- 在文件首行写“#!/usr/bin/env node”。(Linux/Unix系统)
- 在index.js中写上console.log("Hello World!");以展示运行效果。用实际代码替换掉即可。(之后要将这里的代码替换为创建目录及文件的代码。)
- 此时,已完成命令行的编写。只需将当前项目到全局环境,然后就可使用“mycli”命令了。全局安装。在当前目录(即mycli)下执行以下命令以安装。
npm install -g
-
使用:新建一个目录,并运行命令行,在命令行中执行mycli命令。即可看到效果。
-
例子:在index.js中写上创建目录及文件的代码以快速生成项目目录结构及文件。

参考资料:使用Node.js编写CLI工具
流程
- 输入项目类型及项目根目录。
- 根据目录(及文件)结构的模板创建文件夹和文件。
- 输出反馈信息。
代码
创建package.json
- 创建文件夹MakeProject。
- 运行VS Code,通过快捷键Ctrl + ~ 打开终端。在终端中运行命令npm init -y创建package.json。
- 配置package.json如下:
{
"name": "mkproject",
"version": "1.0.0",
"description": "Create node or typescript project automatically",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"bin": {
"mkproject": "./index.js"
},
"author": "",
"license": "ISC"
}
"name"是项目名称。
"version"是项目版本。
"description"是项目的描述。
"scripts"是npm命令脚本,如果改为上面那样,则在终端中可以通过npm run start来运行这个名为start的脚本。
name、version、description和scripts可改可不改。
bin这里一定要修改。mkproject就是之后要使用的node.js cli命令。喜欢的华可以改成自己的。
键盘输入
- 在MakeProject文件夹下创建lib文件夹。然后创建console.js文件。
- 在Node.js中从命令行接收输入。从命令行读取输入是异步地,为了让异步操作能够像同步操作一样按顺序执行这里使用了Promise。
代码如下:参考文档
const readline = require('readline');
/**
* 提示用户在客户端进行输入。
* @param {string} prompt 提示用户进行输入时,需要显示的信息。
* @author kokiafan
* @example
* const readline = require('./lib/console');
*
* async function main() {
* let msg = await readline("请输入一行文字:");
* console.log("刚刚输入的信息:%s", msg);
* }
*
* main();
*/
function readlineAsync(prompt = "Please enter: ") {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise(resolve => {
rl.question(prompt, (data) => {
rl.close();
resolve(data);
})
});
};
module.exports = { readlineAsync };
上面的函数头有JSDoc注释。这个可以给VS Code的Intellisence提供提示信息,有助于调用该函数的程序员使用。参考资料如下:
参考资料
JSDoc的使用:https://www.jianshu.com/p/46519b0499c3
JSDoc的文档:https://www.html.cn/doc/jsdoc/tags-example.html

文件创建
- 在lib文件夹下创建console.js文件。
- 代码如下:
const fs = require('fs');
/**
* 传入一个目录名称字符串数组及根目录名称,异步地创建文件夹。
* @param {string[]} directories
* @param {string} root
* @author kokiafan
* @example
* const io = require('./lib/io');
*
* async function main() {
* io.createDirectories(['dist/css', 'src/css', 'src/html'], './myapps')
* .then(() => console.log('目录创建完成!'));
* }
*
* main();
*/
function createDirectories(directories, root) {
return new Promise(resolve => {
for (let dir of directories) {
let path = root + '/' + dir;
fs.mkdirSync(path, { recursive: true }, error => {
if (error) {
console.log(error);
}
});
console.log(path);
}
resolve(root);
});
}
/**
* 传入一个目录名称字符串数组及根目录名称,异步地创建文件夹。
* @param {{filename:string, content: string}[]} files
* @param {string} root
* @author kokiafan
* @example
* const io = require('./lib/io');
*
* const file1 = { filename: 'text1.txt', content: "hello" };
* const file2 = { filename: 'text2.txt', content: "hello" };
*
* async function main() {
* io.createFiles([file1, file2], '.')
* .then(() => console.log('文件创建完成!'));
* }
*
* main();
*/
function createFiles(files, root) {
return new Promise(resolve => {
for (let file of files) {
let path = root + '/' + file.filename;
fs.writeFile(path, file.content, 'utf8', error => {
if (error) {
console.log(error);
}
});
console.log(path);
}
resolve(root);
});
}
module.exports = {
createDirectories,
createFiles
}
数据准备
- 简单的TypeScript项目:
- 需要创建的文件夹及文件:MakeProject\data\ts\dirs\dirs.js,MakeProject\data\ts\files\files.js,package_json.js,src_index_ts.js,tsconfig_json.js。
- 代码:
dirs.js
// 需要被创建的文件夹
module.exports = ['src'];
files.js
const package_json = require('./package_json');
const tsconfig_json = require('./tsconfig_json');
const index_ts = require('./src_index_ts');
// 需要被创建的文件
const files = [
{ filename: package_json.filename, content: package_json.content },
{ filename: tsconfig_json.filename, content: tsconfig_json.content },
{ filename: index_ts.filename, content: index_ts.content }
];
module.exports = files;
package_json.js
// 声明需要被创建的文件及其内容
const package_json = {
filename: "package.json",
content:
`
{
"name": "ts_app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "npm run build:live",
"build": "tsc",
"build:live": "nodemon --watch src/**/*.ts --exec ts-node src/index.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^14.14.16",
"nodemon": "^2.0.6",
"ts-node": "^9.1.1",
"typescript": "^4.1.3"
}
}
`
};
module.exports = package_json;
src_index_ts.js
// 声明需要被创建的文件及其内容
const src_index_ts = {
filename: "src/index.ts",
content:
`
import * as fs from "fs";
const path = "./message.txt";
const data = "Hello World!";
const encoding = "utf8";
console.log(data);
fs.writeFile(path, data, encoding, error => {
if (error) {
console.log(error);
}
});
`
};
module.exports = src_index_ts;
tsconfig_json.js
// 声明需要被创建的文件及其内容
const tsconfig_json = {
filename: "tsconfig.json",
content:
`
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": [
"es6",
"dom"
], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "lib", /* Redirect output structure to the directory. */
"rootDir": "src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
/* Strict Type-Checking Options */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* Enable strict null checks. */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused locals. */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
/* Module Resolution Options */
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration files to be included in compilation. */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
/* Advanced Options */
"resolveJsonModule": true, /* Include modules imported with '.json' extension */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules"
]
}
`
};
module.exports = tsconfig_json;
- JavaScript Mvc项目:
- 需要创建的文件夹及文件:MakeProject\data\jsmvc\dirs\dirs.js,MakeProject\data\jsmvc\files\files.js,package_json.js,index_js.js。
- 代码:
dirs.js
// 需要被创建的文件夹
module.exports = ['public', 'models', 'views', 'controllers', 'middleware'];
files.js
const package_json = require('./package_json');
const index_js = require('./index_js');
// 需要被创建的文件
const files = [
{ filename: package_json.filename, content: package_json.content },
{ filename: index_js.filename, content: index_js.content }
];
module.exports = files;
package_json.js
// 声明需要被创建的文件及其内容
const package_json = {
filename: "package.json",
content:
`{
"name": "nodejs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \\"Error: no test specified\\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
}
}`
};
module.exports = package_json;
index_js.js
const index_js = {
filename: "index.js",
content:
`
const express = require('express');
const app = express();
const port = process.env.port || 3000;
app.get('/', (request, response) => {
response.send('Hello World');
});
app.listen(port, () => {
console.log(\`Express web app available at localhost: \${port}\`);
});`
}
module.exports = index_js;
- TypeScript项目(VSCode配置 + TypeScript + WebPack + WebPack-Cli + html-webpack + ts-loader + lite-server):
-
需要创建的文件夹及文件:MakeProject\data\tswebpack\dirs\dirs.js,MakeProject\data\tswebpack\files\files.babelrs.js,
, bs_config_json.js,
,dist_css_banner_css.js
,package_json.js
,src_css_banner_css.js
,src_html_index_html.js
,src_ts_app_ts.js
,src_ts_helloworld_ts.js
,src_ts_index_ts.js
,src_ts_slider_ts.js
,src_ts_sum_ts.js
,tsconfig_json.js
,vscode_launch_json.js
,vscode_taskss_json.js
,webpack_config_js.js -
代码:
dirs.js
// 需要被创建的文件夹
module.exports = ['.vscode', 'dist/css', 'src/css', 'src/html', 'src/ts'];
其余的略:
组装程序
将上面的console.js、io.js和data文件夹里的数据组合到程序中,完成整个程序。在MakeProject文件夹下创建index.js文件。代码如下:
#!Node
// #!/usr/bin/env node /linux下这样写
const consoleio = require('./lib/console');
const fsio = require('./lib/io');
/**
* 输入项目类型的字符串,返回项目所需要的文件夹及文件。
* @param {'ts'|'jsmvc'|'tswebpack'} projectType 用户想要的项目类型。
* @return { dirs: string[], files: { filename: string, content: string }[] }
* @author kokiafan
* @example
* let projectType = select('ts');
*/
function select(projectType) {
if (projectType === 'ts') {
return {
dirs: require('./data/ts/dirs/dirs'),
files: require('./data/ts/files/files')
};
}
if (projectType === 'jsmvc') {
return {
dirs: require('./data/jsmvc/dirs/dirs'),
files: require('./data/jsmvc/files/files')
};
}
if (projectType === 'tswebpack') {
return {
dirs: require('./data/tswebpack/dirs/dirs'),
files: require('./data/tswebpack/files/files')
};
}
return null;
}
async function main() {
let root = await consoleio.readlineAsync("请输入项目根目录:");
let type = await consoleio.readlineAsync("请输入项目的类型:(选项ts|jsmvc|tswebpack)");
let projectType = select(type);
if (projectType === null) {
console.log("项目类型错误。")
return;
}
fsio.createDirectories(projectType.dirs, root)
.then(() => fsio.createFiles(projectType.files, root));
}
main();
至此,程序写完。在终端中输入命令npm install -g安装该项目后,即可使用mkproject来创建项目了。

浙公网安备 33010602011771号