详解使用Typescript开发node.js项目(简单的环境配置)


Posted in Javascript onOctober 09, 2017

最近在学习typescript的过程中,想到也许可以使用ts来开发node.js项目。在网上搜了一下,其实已经有很多开发者实践了这方面的内容。这里,我记录一下自己搭建开发环境的简单过程。

使用Typescript开发的好处:

  • 较严格的类型检查和语法检查。
  • 对ES6/ES2015/ES7(部分)支持比较好。
  • 编译后的js文件很干净,也支持多种代码规范。
  • 其他,请参见文档。

准备

  • node.js v6.9.1 或者任意的新版本,老版本暂时没有试验。
  • tsc typescript编译器,使用npm安装:npm install -g typescript,当前是v2.0.10
  • 编辑器:vscode
  • 命令行终端:windows的cmd

特别提示和吐槽:安装tsc可能需要翻墙(如果特别慢的话),所以也可以使用淘宝镜像。

建立node.js项目

使用npm init在指定的目录中建好项目的目录。

在这里我建立了一个自己的项目目录结构:

testTS
|---build         //编译后的js文件目录
|---src          //ts文件目录
|---static        //客户端静态文件
| |---scripts
| |   |---main.js
| |----styles
| |   |---style.css
| |----assets
|---views         //html文件目录
|  |---index.html
|---package.json
|---tsconfig.json

编辑 tsconfig.json

在上面的目录结构中有一个tsconfig.json文件,用来设置ts的编译选项。

想要获取这份文件,可以在项目根目录下使用tsc --init,就会自动建立好一份.tsconfig.json。

编写需要的配置项

默认情况下,tsc会使用默认的编译配置编译目录中的所有.ts文件。通过书写tsconfig.json,我们可以配置tsc的编译行为,达到想要的结果:

{
  "compilerOptions": {
    "module": "commonjs",  //指定生成哪个模块系统代码
    "target": "es6",    //目标代码类型
    "noImplicitAny": false, //在表达式和声明上有隐含的'any'类型时报错。
    "sourceMap": false,   //用于debug  
    "rootDir":"./src",   //仅用来控制输出的目录结构--outDir。
    "outDir":"./build",   //重定向输出目录。  
    "watch":true      //在监视模式下运行编译器。会监视输出文件,在它们改变时重新编译。
  },
  "include":[
    "./src/**/*"
  ],
  "exclude":[
    "views",
    "static"
  ]
}

配置文件注意点

"compilerOptions"是编译选项,具体详情,请参见:

中文文档
英文文档

"module"是用来指定设置编译后的js代码,使用何种模块规范。由于是开发node.js项目,所以选择commonjs。(有兴趣的话,可以把所有module所有可能的值都试一遍,查看编译后的js文件的差别,会发现生成的代码还是很不错的,很干净。)

"target"是编译后的js代码遵循何种规范,可以是es3/es5/es6等等,这里为了对比ts 2.0代码和es6代码的不同,使用了"es6"。

"rootDir"是一个需要注意的地方,它会告诉编译器,此目录下的文件需要经过编译。那么,如果设置了这个选项,又在外部(比如根目录)放置了.ts文件,会怎么样呢?tsc会提示一条类似这样的错误:

"error TS6059: File 'D:/workplace/nodeWP/testTS/index.ts' is not under 'rootDir' 'D:/workplace/nodeWP/testTS/src'. 'rootDir' is expected to contain all source files."

并且,在build的目录中,输出的目录结构也会变化:

 详解使用Typescript开发node.js项目(简单的环境配置)

这显然不是我们想要的结果。

解决方案是使用include和exclude属性。按照文档说明,"include" 和 "exclude" 属性指定一个文件glob匹配模式列表。表明需要包含的文件目录或文件,以及需要过滤掉的文件或目录(也可以使用"files"配置项,不过需要一个一个文件录入,"files" 属性明确指定的文件却总是会被包含在内,不管 "exclude" 如何设置。),详见官方文档说明。

所以,添加"./src/**/*"到"include"所指向的数组,就可以指定./src下的所有文件,是我们真正需要被编译的,其他目录将会被排除。

"outDir" 指向了编译后的js代码输出的地方。在文档中也有"outFile"选项,可以把所有的ts文件按照一定顺序规则打包成一个文件,具体可以参考文档。在这里,我们优先使用outDir。

试验一下

在书写完2个配置文件之后,就可以开始撰写代码,并执行编译了。我们试验一下:

在./src/server.ts中,写一段简单的:

interface ICache{
  useCache:boolean;
  [propName:string]:any;
}
const cache:ICache = {useCache:true};

之后,在终端中输入:

D:\workplace\nodeWP\testTS>tsc

经过编译,会生成server.js到build目录中:

//server.js
const cache = { useCache: true };

使用.d.ts文件

既然要开发一个项目,显然不会只有这些代码。肯定要用到内建模块和第三方模块。然而,直接导入模块,在.ts文件中是不行的。例如:

详解使用Typescript开发node.js项目(简单的环境配置)

这是由于typescript自身的机制,需要一份xx.d.ts声明文件,来说明模块对外公开的方法和属性的类型以及内容。感觉有一些麻烦。好在,官方以及社区已经准备好了方案,来解决这个问题。

在TypeScript 2.0以上的版本,获取类型声明文件只需要使用npm。在项目目录下执行安装:

npm install --save-dev @types/node

就可以获得有关node.js v6.x的API的类型说明文件。之后,就可以顺利的导入需要的模块了:

import * as http from 'http';

完成之后,不仅可以正常的使用http模块中的方法,也可以在vscode中获得相应的代码提示。

对于内建模块,安装一个@types/node模块可以整体解决模块的声明文件问题。那么,对于浩如烟海的第三方模块,该怎么办呢?官方和社区中也提供了查找和安装的渠道:

  • typings
  • DefinitelyTyped
  • TypeSearch

自动编译和自动重启服务

解决完了声明文件之后,其实我们已经可以使用ts简单的进行node.js项目的开发了。但是,每次写完或者修改代码,就要编译,然后再启动,是一件不大但是相当让人烦躁的事情。为了效率,我们应当改善它。

首先,要让.ts文件可以自动被编译。这在上文中的tsconfig.json文件中,已经被设置好了,就是"watch":true 。此时在命令行执行tsc命令后,编译器就会时时监控目录中.ts文件的变化,然后自动编译。

自动重启node服务器,我们可以使用 supervisor 模块解决,或者任何具有类似功能的解决方案都可以。

全局安装supervisor模块npm install -g supervisor,之后就可以在终端中使用supervior ./build/server.js启动服务器,并在服务器端代码改变之后,自动重启服务器。

让启动服务更简单

由于以上的2个命令,在启动时都可能需要附加一些参数,每次输入很麻烦。

可以使用npm script来解决。在package.json文件中的"scripts"中,我们设置:

{
  "scripts":{
    "dev": "supervisor -w build ./build/server.js",
    "build": "tsc",
  }
}

执行npm run dev之后,如果./build目录中的.js文件发生改变时,就会重启服务器。

执行npm run build时,则只会编译ts文件并监控ts的改变。

使用例子来试验一下

import * as http from 'http';
//====================
const server = http.createServer(function(request:http.IncomingMessage,response:http.ServerResponse):void{
  console.log("create a server...");
  response.writeHead(200,{'Content-Type':'text/plain'});
  response.write('Hello world,we use typescript to develop.');
  response.end();
});

server.listen(3000,function(){
  console.log("Server listening on port 3000");
  console.log("test...");
});

补充:一个命令实现tsc编译和重启服务器

2017.5.3更新:

感谢大家对本文的支持。有朋友(@Ajaxyz)提出,有没有办法将ts编译监视和重启服务器合并为一个命令?

这里提出一个比较简易的方法,使用gulp来管理这2个流程。(如何使用gulp工作,请参考Gulp API)

1. 使用gulp的watch()来监控ts文件的变化并重启服务器。

这种方式,需要使用gulp和gulp-typescript插件(安装)

注意的一点是:gulp-typescript可能需要在项目的目录安装typescript,所以可以在项目的目录中,运行命令行:

npm install typescript

准备好gulp和插件之后,需要书写一份gulpfile.js作为gulp项目需要执行的任务文件,例子如下:

//gulpfile.js
  
  let gulp = require('gulp');
  let ts = require('gulp-typescript');
  let tsp = ts.createProject('tsconfig.json'); //使用tsconfig.json文件配置tsc
  let exec = require('child_process').exec;
  
  let child;
  //目录常量
  const PATHS = {
    scripts:['./src/**/*.ts'],
    output:'./build',
  };
  //编译ts文件
  gulp.task('build-ts',['restart'],function(){
    return gulp.src(PATHS.scripts)
      .pipe(tsp())
      .pipe(gulp.dest(PATHS.output));  
  });
  //监视ts文件变化
  gulp.task('watch-ts',['build-ts'],function(){  
    gulp.watch(PATHS.scripts,['build-ts']);
  });
  //自动重启服务器
  gulp.task('restart',function(){
    child = exec('supervisor -w build ./build/server.js',(error,stdout,stderr)=>{
      console.log(`stdout: ${stdout}`);
      console.log(`stderr: ${stderr}`);
      if (error !== null) {
        console.log(`exec error: ${error}`);
      }
    });
  });
  //开发任务
  gulp.task('dev',['build-ts','restart','watch-ts']);

这样,在开发时,直接在项目目录运行gulp dev,就可以启动编译和服务器了。此后,gulp会监视ts文件的改动,然后编译ts文件并重启服务器。刷新页面,就可以看到新结果已经输出在浏览器页面中了。

还有一点需要留意的是,由于gulp负责监视ts文件的变化,因此请在tsconfig.json将"watch"设置为false或者删掉这个属性。

2. 使用tsconfig.json监控ts文件变化并重启服务器

用这种方式,首先打开tsconfig.json对ts文件的监视,然后修改gulpfile.js文件,如下:

//...requier部分同上面例子,这里省略
  
  let tsChild,    //监视ts文件修改子进程
    serverChild;  //重启服务器子进程
  //编译ts文件
  gulp.task('build-ts',function(){
     tsChild = exec('tsc',(error,stdout,stderr)=>{
      console.log(`tsc====>stdout: ${stdout}`);
      console.log(`tsc====>stderr: ${stderr}`);
      if (error !== null) {
        console.log(`exec error: ${error}`);
      }
    });
  });
  //自动重启服务器
  gulp.task('restart',function(){
    serverChild = exec('supervisor -w build ./build/server.js',(error,stdout,stderr)=>{
      console.log(`restart=====>stdout: ${stdout}`);
      console.log(`restart=====>stderr: ${stderr}`);
      if (error !== null) {
        console.log(`exec error: ${error}`);
      }
    });
  });
  //开发任务
  gulp.task('dev2',['build-ts','restart']);

运行gulp dev2,效果和上一个例子一样。

以上,提供一种解决办法的方式和思路,仅供参考,如果用在实际环境中,还需要进一步完善功能。

结语

本文只是对搭建typescript开发node.js项目的环境做一个简单研究和记录。

最初这样想,也只是好奇可不可以这么做。实际上在node.js稳定版本v6.9.1中已经支持了90%的ES6。因此,直接使用ES6开发node.js项目,是很好的选择。

不完善的地方,请见谅,后面会慢慢补充。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
图片在浏览器中底部对齐 解决方法之一
Nov 30 Javascript
浅析node.js中close事件
Nov 26 Javascript
jQuery实现瀑布流布局详解(PC和移动端)
Sep 01 Javascript
详解使用vue脚手架工具搭建vue-webpack项目
May 10 Javascript
vue的状态管理模式vuex
Nov 30 Javascript
微信小程序简单实现form表单获取输入数据功能示例
Nov 30 Javascript
js动态添加表格逐行添加、删除、遍历取值的实例代码
Jan 25 Javascript
微信小程序url传参写变量的方法
Aug 09 Javascript
在iFrame子页面里实现模态框的方法
Aug 17 Javascript
Vue源码解析之Template转化为AST的实现方法
Dec 14 Javascript
JS多个异步请求 按顺序执行next实现解析
Sep 16 Javascript
使用vue-router切换页面时实现设置过渡动画
Oct 31 Javascript
JS中Attr的用法详解
Oct 09 #Javascript
移动端效果之Swiper详解
Oct 09 #Javascript
浅谈node的事件机制
Oct 09 #Javascript
JS实现中文汉字按拼音排序的方法
Oct 09 #Javascript
ES6中的Promise代码详解
Oct 09 #Javascript
js+html5生成自动排列对话框实例
Oct 09 #Javascript
jQuery实现获取table中鼠标click点击位置行号与列号的方法
Oct 09 #jQuery
You might like
PHP实现无限分类的实现方法
2016/11/14 PHP
Laravel模型事件的实现原理详解
2018/03/14 PHP
PHP中的Iterator迭代对象属性详解
2019/04/12 PHP
JQuery.uploadify 上传文件插件的使用详解 for ASP.NET
2010/01/22 Javascript
jquery.cvtooltip.js 基于jquery的气泡提示插件
2010/11/19 Javascript
JQuery触发事件例如click
2013/09/11 Javascript
响应式表格之固定表头的简单实现
2016/08/26 Javascript
解决webpack打包速度慢的解决办法汇总
2017/07/06 Javascript
利用Vue实现移动端图片轮播组件的方法实例
2017/08/23 Javascript
webpack构建换肤功能的思路详解
2017/11/27 Javascript
javascript+css3开发打气球小游戏完整代码
2017/11/28 Javascript
js实现文件上传功能 后台使用MultipartFile
2018/09/08 Javascript
JavaScript函数定义方法实例详解
2019/03/05 Javascript
一次让你了解全部JavaScript的作用域
2019/06/24 Javascript
简单了解JavaScript sort方法
2019/11/25 Javascript
详解三种方式在React中解决绑定this的作用域问题并传参
2020/08/18 Javascript
[01:03:00]DOTA2上海特级锦标赛A组败者赛 EHOME VS CDEC第一局
2016/02/25 DOTA
Python中的tuple元组详细介绍
2015/02/02 Python
python分析nignx访问日志脚本分享
2015/02/26 Python
python编辑用户登入界面的实现代码
2018/07/16 Python
浅析PEP572: 海象运算符
2019/10/15 Python
python 字典访问的三种方法小结
2019/12/05 Python
Django模型中字段属性choice使用说明
2020/03/30 Python
Steve Madden官网:美国鞋类品牌
2017/01/29 全球购物
Jack Rogers官网:美国经典的女性鞋靴品牌
2019/09/04 全球购物
Unix里面如何在后台运行程序
2016/10/14 面试题
医药专业应届毕业生求职信范文
2014/01/01 职场文书
会计电算化应届生自荐信
2014/02/25 职场文书
一年级学生评语大全
2014/04/21 职场文书
工程材料采购方案
2014/05/18 职场文书
迎新晚会策划方案
2014/06/13 职场文书
2015年仓库管理员工作总结
2015/04/21 职场文书
2016猴年春节问候语
2015/11/11 职场文书
MySQL之PXC集群搭建的方法步骤
2021/05/25 MySQL
解析mybatis-plus中的resultMap简单使用
2021/11/23 Java/Android
Python之Matplotlib绘制热力图和面积图
2022/04/13 Python