详解使用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 相关文章推荐
JavaScript面向对象之体会[总结]
Nov 13 Javascript
JS中自定义定时器让它在某一时刻执行
Sep 02 Javascript
关于javascript的一些知识以及循环详解
Sep 12 Javascript
jQuery图片轮播(二)利用构造函数和原型创建对象以实现继承
Dec 06 Javascript
vue2笔记 — vue-router路由懒加载的实现
Mar 03 Javascript
微信小程序开发之animation循环动画实现的让云朵飘效果
Jul 14 Javascript
微信小程序实现添加手机联系人功能示例
Nov 30 Javascript
详解如何实现一个简单的 vuex
Feb 10 Javascript
详解vue2.0 不同屏幕适配及px与rem转换问题
Feb 23 Javascript
jQuery实现通过方向键控制div块上下左右移动的方法【测试可用】
Apr 26 jQuery
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
Mar 29 Javascript
Vue与React的区别和优势对比
Dec 18 Vue.js
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网上调查系统
2006/10/09 PHP
PHP抽象类 介绍
2012/06/13 PHP
编译PHP报错configure error Cannot find libmysqlclient under usr的解决方法
2014/06/27 PHP
Apache服务器下防止图片盗链的办法
2015/07/06 PHP
PHP QRCODE生成彩色二维码的方法
2016/05/19 PHP
Jquery iframe内部出滚动条
2010/02/11 Javascript
js prototype截取字符串函数
2010/04/01 Javascript
IE6下通过a标签点击切换图片的问题
2010/11/14 Javascript
javascript判断移动端访问设备并解析对应CSS的方法
2015/02/05 Javascript
基于javascript制作微信聊天面板
2020/08/09 Javascript
AngularJS基础 ng-mouseleave 指令详解
2016/08/02 Javascript
Vue表单实例代码
2016/09/05 Javascript
详解angular中如何监控dom渲染完毕
2017/01/03 Javascript
bootstrap折叠调用collapse()后data-parent不生效的快速解决办法
2017/02/23 Javascript
vue.js 获取当前自定义属性值
2017/06/01 Javascript
vue router 源码概览案例分析
2018/10/09 Javascript
详解使用JWT实现单点登录(完全跨域方案)
2019/08/02 Javascript
使用Karma做vue组件单元测试的实现
2020/01/16 Javascript
pymongo实现多结果进行多列排序的方法
2015/05/16 Python
python使用pymysql实现操作mysql
2016/09/13 Python
python游戏地图最短路径求解
2019/01/16 Python
python3连接mysql获取ansible动态inventory脚本
2020/01/19 Python
TensorFlow实现打印每一层的输出
2020/01/21 Python
使用phonegap进行本地存储的实现方法
2017/03/31 HTML / CSS
荷兰皇家航空公司官方网站:KLM Royal Dutch Airlines
2017/12/07 全球购物
英国天然抗衰老护肤品品牌:Nakin Skin Care
2019/04/16 全球购物
strlen的几种不同实现方法
2013/05/31 面试题
高级Java程序员面试要点
2013/08/02 面试题
初中生个人学习的自我评价
2013/12/04 职场文书
应用化学专业职业生涯规划书
2013/12/31 职场文书
学生会主席事迹材料
2014/01/28 职场文书
安全生产检查通报
2014/01/29 职场文书
司机岗位职责说明书
2014/07/29 职场文书
个人创业事迹材料
2014/12/30 职场文书
社区服务活动报告
2015/02/05 职场文书
vue el-table实现递归嵌套的示例代码
2022/08/14 Vue.js