TS开发环境运行方式对比

598 阅读3分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

ts-node可以直接运行ts文件,但是浏览器不能直接运行ts,需要转成js。js有不同的规范,所以ts转js时,可以转换的目标规范也可以不同,具体配置如图所示:

ic_tsc_10.png

以下三种实现方式

  • 命名空间使用:CommonJS规范
  • import方式引入:ES6 Module,转译成AMD规范
  • Parcel打包使用:打包工具方式

命名空间使用

  • 没有命名空间
    • 编译后都是var声明的全局变量,过多的全局变量会让代码变得不可维护
  • 有命令空间
    • 通过 namespace 定义,通过 export 暴露出去
    • 只有暴露出去才是全局的,其他的不会造成全局污染
    • 减少全局变量,实现基本的封装
  1. 新增 src/components.ts 文件:组件化实现,每个类(class)都使用了 export 导出,采用了命名空间(namespace)
namespace Components {
  export class Header {
    constructor() {
      const elem = document.createElement("div");
      elem.innerText = "This is Header";
      document.body.appendChild(elem);
    }
  }

  export class Content {
    constructor() {
      const elem = document.createElement("div");
      elem.innerText = "This is Content";
      document.body.appendChild(elem);
    }
  }

  export class Footer {
    constructor() {
      const elem = document.createElement("div");
      elem.innerText = "This is Footer";
      document.body.appendChild(elem);
    }
  }
}
  1. 新增 src/page.ts 文件
namespace Home {
  export class Page {
    constructor() {
      new Components.Header();
      new Components.Content(); 
      new Components.Footer(); 
    }
  }
}
  1. 新增 index.html 文件
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    // 引入文件
    <script src="./build/page.js"></script>
    <title>Document</title>
  </head>
  <body>
    // 执行文件
    <script>new Home.Page();</script>
  </body>
</html>
  1. 编辑 tsconfig.json 文件 outFile 配置项:用来处理多个文件生成一个文件,避免每次增加文件都要在入口文件 index.html 中引入一下
  • 使用前:生成 build/page.jsbuild/components.js两个文件,index.html 中也需要引入两个
  • 使用后,仅生成 build/page.js 文件,而且要更改"module":"amd"配置,由commonjs改为amd
{ 
  "compilerOptions": { 
    // "module": "commonjs"
    "module": "amd",
    "outFile": "./build/page.js", /* 生成一个文件 */
    "rootDir": "./src", /* ts文件位置目录 */
    "outDir": "./build", /* 编译后js文件存放目录 */   
  }
}
  1. 运行效果
tsc // ts文件编译为js文件
open index.html // 打开页面,查看效果

ic_tsc_6.png

import方式引入

  • CommonJS:浏览器不支持,用于服务端,如NodeJS,webpack;通过require同步加载模块,通过 exports 或 module.exports 导出
  • AMD:异步模块定义,支持浏览器端,RequireJS;通过define定义模块,require加载模块;提前执行,依赖前置
  • CMD:同步模块定义,支持浏览器端,SeaJS;延迟执行,依赖就近;
  • ES6 Module:import/export;无法直接在浏览器中执行,需要转译
  1. 修改 src/components.ts 文件,去除空间namespace,直接使用 ES6 的 export 导出

  2. 修改 src/page.ts 文件,通过 ES6 的 import 引入

import { Header, Content, Footer } from "./components"; 
// 必须要加 default 关键字,才能引用到
export default class Page { 
  constructor() {
    new Header(); 
    new Content(); 
    new Footer(); 
  }
}

问题:使用tsc命令编译后生成 build/*.js 文件,打开 index.html 会报错。

原因:编译好的代码都是define开头的( AMD 规范),可以在 Node 中直接运行,*不能直接在浏览器中运行*,需要其他库(如require.js)的支持

ic_tsc_7.png

  1. 修改index.html文件:修改完成后可以正常显示
<head>
  // 引入require.js,浏览器就可以正常解析 define 语法了
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.js"></script>
</head>
<body>
  <script>
    // 执行方式也需要修改
    require(["page"], function (page) {
      new page.default();
    });
  </script>
</body>

Parcel打包使用

上面通过 require 方式引入,用起来步骤太多,比较麻烦。

可以通过 webpackParcel 打包工具处理,简化流程。

Parcel官网地址:v2.parceljs.cn/getting-sta…

还是借助上面 tsdemo 示例进行改造:

  1. 更改index.html文件,直接引入ts文件;且移动到src目录下
<html lang="en">
  <head>
    // ...
    // 必须要加type="module",不然会报错
    // page.ts最后面加上 "new Page()", 执行代码
    <script type="module" src="./page.ts"></script>
  </head>
</html>
  1. 修改tsconfig.json配置文件:只更改 rootDir 的值,其他的还原
{ 
  "compilerOptions": { 
    "module": "commonjs"
    // "module": "amd",
    // "outFile": "./build/page.js",
    "rootDir": "./src",
    // "outDir": "./build",  
  }
}
  1. 安装Parcel
// yarn 安装
yarn add --dev parcel
// 或者 npm 安装
npm install --save-dev parcel
  1. 修改package.json文件
{
  "name": "tsdemo",
  "version": "1.0.0",
  "source": "src/index.html", // add
  "scripts": {
    "start": "parcel", // add
    "build": "parcel build" // add
  },
  "devDependencies": {
    "parcel": "^2.0.1" // add
  }
}
  1. 启动服务
// 运行命令
npm run start
// 打开页面访问 
http://localhost:1234

报错如下图所示: @parcel/transformer-js: Browser scripts cannot have imports or exports.

ic_tsc_8.png

报错原因:代码中用到了ES6的import/export,Parcel不支持

解决办法:就是引入ts文件时,添加 type="module"

  1. 效果展示

ic_tsc_9.png