typescript 模块系统-从 JavaScript 到 TypeScript - 模块化和构建

2023-08-27 0 5,668 百度已收录

TypeScript 最大的好处就是静态类型检测,所以在从 JavaScript 切换到 TypeScript 之前,必须意识到添加类型定义会带来额外的工作量,这是必要的代价。 然而,静态类型检查所带来的好处是值得的。 事实上,TypeScript 允许不定义一个类型或者将所有类型定义为any,但如果这样做的话,TypeScript 带来的大部分静态检测功能都会失效。 换句话说,不需要使用 TypeScript。

模块化的

转换之前需要注意的另一个问题是模块化。 早期的 JavaScript 代码基本上每个 HTML 页面对应一个或多个 JavaScript 脚本,当时的 JavaScript 代码几乎没有模块化的概念。 然而,随着Web 2.0的盛行,很多工作从前端转移到了后端,JavaScript程序变得越来越复杂,模块化成为刚需,大量的模块化框架应运而生。突然间,其中比较有名的就是RequestJS及其带来的AMD标准,以及SeaJS带来的CMD标准。 随着 Node.js 和 JavaScript 全栈的流行typescript 模块系统,出现了 CommonJS 标准。 后来出现了广泛使用的SystemJS。 事实上,ES6模块化标准是不可或缺的,尽管Node. Node.js 和大多数浏览器目前还不支持。

TypeScript 本身支持两种形式的模块化,一种是对 ES6 模块的小扩展,另一种是在 ES6 发布之前模仿 C# 的命名空间。 大部分使用命名空间的场景都可以被ES6模块化标准替代。 我们先来看看两种模块化形式的区别。

命名空间

命令空间中编写的TS脚本翻译成JS后,可以直接加载到页面上,无需使用任何模块加载框架。 但不幸的是,这些方法中带有通配符的JS程序不能直接在Node.js中使用。 因为tsc不会生成modules.exports对象以及使用命名空间的模块的require语句。

有一个例外。 将所有.ts文件翻译成.js,假设名为all.js,这样就可以被nodeall运行了。 这些情况不需要任何模块导出和导入。

但在浏览器环境下,严格按照依赖顺序导入生成的.js文件是可行的。 前期可以采用“命名空间”形式的模块化编写,无需使用模块化的JS文件,甚至可以将几百行、几千行的小JS源文件拆分成几个小TS文件,然后通过tsc- - outfile输出单个JS文件供使用,无需改变原始HTML(或其他动态页面文件)的代码,即可实现模块化构建

typescript 模块系统-从 JavaScript 到 TypeScript - 模块化和构建

另外需要注意的是,当指定单个输出文件时,TypeScript 不会通过代码逻辑检测模块之间的依赖关系。 默认情况下,它将按文件名的字母顺序一一转译 .ts 文件,除非通过源文件中的 /// 显式指定依赖项。

ES6模块

当 TypeScript 使用 ES6 模块句型实现模块化时,tsc 允许 module 参数指定生成的 .js 将应用到哪个模块化框架。 默认是commonjs,其他常用的还有amd、system等。

其实,如果原来的JS程序使用AMD框架,转换为TS时,可以使用ES6模块的编写方式,使用tsc--moduleamd输出对应的JS文件,不需要改变原来的页面文件。

但如果原来的JS文件没有使用任何模块框架,那么转换成ES6模块编写的TS代码时创建起来就会麻烦一些。 在这些情况下,虽然创建了单个输出文件,但仍然需要模块化框架的支持,例如AMD的define和require,或者System的API支持。

为了防止引入模块化框架,可以考虑用commonjs标准输出JS,然后使用Webpack将所有生成的JS打包到一个文件中。 由于这里使用了Webpack,因此创建配置更加灵活。 由于 Webpack 可以指定多个条目和多个输出,因此它会通过 require(...) 翻译为 import... 来手动检测依赖关系。并且 Webpack 还可以使用 ts-loader 直接处理 .ts 文件,而无需先使用 tsc 进行翻译。 如果在 TS 中使用更高版本的 ECMAScript 句型,比如 async/await,还可以使用 babel-loader 来减少一层处理……非常灵活。

typescript 模块系统-从 JavaScript 到 TypeScript - 模块化和构建

但这里经常出现一个问题,生成的.js中的所有定义都不在全局范围内,那么脚本导入到网页后,如何使用其中定义的内容呢? 这就需要用到全局对象window了——这里不需要考虑Node.js的全局对象global,因为在Node.js下通常是以模块化的形式引入的,不需要向其中注入任何东西全局对象。

向窗口注入对象(或函数、值等)的方式也很简单,就两步:声明和赋值,例如:

import MyApi from "./myapi";
declare global {
    interface Window {
        mime: MyApi;
    }
}
window.mime = new MyApi();

常用的构建配置

我们在早期项目中使用了 TypeScript 命名空间typescript 模块系统,但最近它们几乎被重构为 ES6 模块。 由于使用了异步函数,TypeScript 通常配置为输出 ES2017 代码,然后由 Babel 翻译为 ES5 代码,最后由 Webpack 打包输出。

tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es2017",
        "lib": [
            "dom",
            "es6",
            "dom.iterable",
            "scripthost",
            "es2017"
        ],
        "noImplicitAny": false,
        "sourceMap": false
    }
}

当目标是 es5 或 es6 时,TypeScript 会有一个默认的 lib 列表,官方文档中有详细解释。 target定义为es2017来支持异步函数,但是这个配置没有默认的lib列表,所以要参考官方文档--targetes6使用的lib列表,并添加es2017类型库。

webpack.config.js

这里使用Webpack2的配置格式。

module.exports = {
    entry: {
        index: "./js/index"
    },
    output: {
        filename: "[name].js"
    },
    devtool: "source-map",
    resolve: {
        extensions: [".ts"]
    },
    module: {
        rules: [
            {
                test: /.ts$/,
                use: [
                    {
                        loader: "babel-loader",
                        options: {
                            presets: ["es2015", "stage-3"]
                        }
                    },
                    "ts-loader"
                ],
                exclude: /node_modules/
            }
        ]
    }
};

吞咽任务

typescript 模块系统-从 JavaScript 到 TypeScript - 模块化和构建

如果还是用gulp的话,任务是这样写的

const gulp = require("gulp");
const gutil = require("gulp-util");
// 转译JavaScript
gulp.task("webpack", () => {
    const webpack = require("webpack-stream");
    const config = require("./webpack.config.js");
    return gulp.src("./js/**/*.ts")
        .pipe(webpack(config, require("webpack")))
        .on("error", function(err) {
            gutil.log(err);
            this.emit("end");
        })
        .pipe(gulp.dest("../www/js"));
});

这里需要注意的是,webpack-stream默认使用webpack1,而我们的配置需要webpack2,所以为其指定第二个参数,即特定版本的webpack实例(通过require("webpack")导出)。

所需的节点模块

从里面的构建配置就不难总结出创建过程中需要安装的Node模块了。 有一些

直接在Node.js环境中运行.ts

在 Node.js 中,通过 ts-node 包可以直接运行 TypeScript 代码。需要做的就是在入口代码文件中添加一句(实际上是 .js 代码)

require('ts-node').register({ /* options */ })

或者

require('ts-node/register')

由于Node.js7.6已经直接支持了async function句型,所以即使使用这个句型,也不用担心ts-node在显存中的翻译结果跑不起来。

入口文件仍然必须是 .js 文件,这是一个小小的遗憾,但是对于使用 Node.js 编写构建脚本的用户来说,有两个好消息:gulp 和 webpack 都直接支持 .ts 入口(或配置)文件.例如,以gulp为例,可以定义gulpfile.ts(注意扩展名是.ts)如下

import * as gulp from "gulp";
gulp.task("hello", () => {
    console.log("hello gulp");
});

不过,gulp 也是通过 ts-node 模块使用 TypeScript,而 ts-node 的功能依赖于 typescript,所以不要忘记安装这两个模块。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

悟空资源网 typescript typescript 模块系统-从 JavaScript 到 TypeScript - 模块化和构建 https://www.wkzy.net/game/166580.html

常见问题

相关文章

官方客服团队

为您解决烦忧 - 24小时在线 专业服务