「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战」
ts-node可以直接运行ts文件,但是浏览器不能直接运行ts,需要转成js。js有不同的规范,所以ts转js时,可以转换的目标规范也可以不同,具体配置如图所示:
以下三种实现方式
- 命名空间使用:CommonJS规范
- import方式引入:ES6 Module,转译成AMD规范
- Parcel打包使用:打包工具方式
命名空间使用
- 没有命名空间
- 编译后都是
var
声明的全局变量,过多的全局变量会让代码变得不可维护
- 编译后都是
- 有命令空间
- 通过
namespace
定义,通过export
暴露出去 - 只有暴露出去才是全局的,其他的不会造成全局污染
- 减少全局变量,实现基本的封装
- 通过
- 新增
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);
}
}
}
- 新增
src/page.ts
文件
namespace Home {
export class Page {
constructor() {
new Components.Header();
new Components.Content();
new Components.Footer();
}
}
}
- 新增
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>
- 编辑 tsconfig.json 文件
outFile
配置项:用来处理多个文件生成一个文件,避免每次增加文件都要在入口文件index.html
中引入一下
- 使用前:生成
build/page.js
和build/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文件存放目录 */
}
}
- 运行效果
tsc // ts文件编译为js文件
open index.html // 打开页面,查看效果
import方式引入
CommonJS
:浏览器不支持,用于服务端,如NodeJS,webpack;通过require同步加载模块,通过 exports 或 module.exports 导出AMD
:异步模块定义,支持浏览器端,RequireJS;通过define定义模块,require加载模块;提前执行,依赖前置CMD
:同步模块定义,支持浏览器端,SeaJS;延迟执行,依赖就近;ES6 Module
:import/export;无法直接在浏览器中执行,需要转译
-
修改
src/components.ts
文件,去除空间namespace
,直接使用 ES6 的export
导出 -
修改
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
)的支持
- 修改
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
方式引入,用起来步骤太多,比较麻烦。
可以通过 webpack
和 Parcel
打包工具处理,简化流程。
Parcel官网地址:v2.parceljs.cn/getting-sta…
还是借助上面 tsdemo 示例进行改造:
- 更改index.html文件,直接引入ts文件;且移动到src目录下
<html lang="en">
<head>
// ...
// 必须要加type="module",不然会报错
// page.ts最后面加上 "new Page()", 执行代码
<script type="module" src="./page.ts"></script>
</head>
</html>
- 修改tsconfig.json配置文件:只更改 rootDir 的值,其他的还原
{
"compilerOptions": {
"module": "commonjs"
// "module": "amd",
// "outFile": "./build/page.js",
"rootDir": "./src",
// "outDir": "./build",
}
}
- 安装Parcel
// yarn 安装
yarn add --dev parcel
// 或者 npm 安装
npm install --save-dev parcel
- 修改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
}
}
- 启动服务
// 运行命令
npm run start
// 打开页面访问
http://localhost:1234
报错如下图所示: @parcel/transformer-js: Browser scripts cannot have imports or exports.
报错原因:代码中用到了ES6的import/export,Parcel不支持
解决办法:就是引入ts文件时,添加 type="module"
- 效果展示