赞
踩
在讲模块化之前,我们线了解一些前端领域中有哪些模块化标准:ES6、commonjs、amd、umd、system、esnext(这个还没有正式成为模块化标准)
那么这么多模块化标准,我们在TS中所讨论的是ES6和commonjs,他们是如何书写模块化语句?书写完成后编译结果是如何的
TS中,导入和到处模块化,同一使用ES6的模块化标准,如下例子
- //myModule.ts文件
- export function sum(a:number,b:number):number{
- return a+b
- }
- export const name="井底的蜗牛"
-
- //index.ts 文件
- import {name, sum} from "./myModule";
- console.log(sum(3,4))
- console.log(name)
在使用导出的函数和变量时,你会发现它会自动帮你把import {name, sum} from "./myModule";
导入,不需要手动导入
当然前提条件是,在导出的时候,导出的是一个声明export 声明变量/函数
,而不是默认导出的形式export defailt {}
如:
- //myModule.ts文件
- export default {
- name:'井底的蜗牛',
- sum(a:number,b:number):number{
- return a+b
- }
- }
因为默认导出的对象是没有名字的,所以在导入时,是可以更改导入的名字的,所以无法享受到它的自动导入
- //index.ts 文件
- import myModule from "./myModule";
- console.log(myModule.sum(3,4))
- console.log(myModule.name)
这里值得注意:在导入的时候,文件名字不要加后缀名import myModule from "./myModule.ts";
因为在编译结果中是没有ts文件的 你加入ts后缀编译后根本找不到该文件这样必定报错
在TS中使用模块还是挺简单的,就使用ES6的模块化标准就可以了
到了js代码中,世界其实没有那么清净的,本来我们写代码的时候都使用的是ES6模块化标准,但到了真实的世界是混乱的,一会儿是ES6标准,一会儿是commonjs标准,那么编译结果里面是怎么处理的,使用的是什么模块化标准呢?
首先编译结果是可以配置的,啥意思呢,就是编译结果使用ES6还是commonjs标准是可以进行配置的,既然可以配置那么在哪里配置呢,既然是配置那肯定是配置文件了
我们可以在TS的配置文件tsconfig.json
中进行配置,是哪个配置呢,就是module
这个配置
- {
- "compilerOptions": {
- "target": "es2016",//配置编译目标代码的版本标准
- "module": "commonjs",//配置编译目标使用的模块化标准
- "lib": ["es2016"], //表示默认详情下ts使用的是那一个环境
- "outDir": "./dist",//编译结果的目录
- "strictNullChecks": true,//TS检查变量是否是null
- "removeComments": true,/*编译结果中是否移除注释*/
- "noImplicitUseStrict": true,/*编译结果中是否有"use strict"*/
- },
- "include":["./src/index.ts"],//执行ts的目录
- }
当我们配置为"module": "commonjs"
时,编译的结果使用的就是commonjs的标准,这里使用的是声明变量导出,编译的结果如
- //编译后的myModule.js文件
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.name = exports.sum = void 0;
- function sum(a, b) {
- return a + b;
- }
- exports.sum = sum;
- exports.name = "井底的蜗牛";
-
- //编译后的index.js文件
- Object.defineProperty(exports, "__esModule", { value: true });
- const myModule_1 = require("./myModule");
- console.log((0, myModule_1.sum)(1, 4));
- console.log(myModule_1.name);
当我们的文件使用的是默认导出,编译的结果如下:
在原文件myModule.ts 在该文件中加入一个默认导出一个函数
- //原文件myModule.ts
- export function sum(a:number,b:number):number{
- return a+b
- }
- export let name="井底的蜗牛"
- export default function (){
- console.log("this is myModule!")
- }
结果编译结果中就变成了这样,我们可以看出,由于commonjs导出的是一个exports对象,所以默认的导出会变成exports的default属性
- //编译后的myModule.js
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.name = exports.sum = void 0;
- function sum(a, b) {
- return a + b;
- }
- exports.sum = sum;
- exports.name = "井底的蜗牛";
- function default_1() {
- console.log("Hello myModule!");
- }
- exports.default = default_1;
我们在导入时给默认导出的函数命名为sayHell
- //原文件index.ts
- import sayHell,{name, sum} from "./myModule";
-
- console.log(sum(1,4))
- console.log(name)
- sayHell()
结果到编译结果中,commonjs导入的是myModule_1整个对象,而刚刚命名的默认导出的名字就变成了,myModule_1.default()执行,因为导出的时候就是这样导出的, 所以在导入的时候,不管你名字是啥,编译后都是myModule_1.default
- //编译后的index.js
- Object.defineProperty(exports, "__esModule", { value: true });
- const myModule_1 = require("./myModule");
- console.log((0, myModule_1.sum)(1, 4));
- console.log(myModule_1.name);
- (0, myModule_1.default)();
在配置编译结果为es6时,发现导出时的编译结果和原文件一模一样
- //原文件 myModule.ts
- export function sum(a:number,b:number):number{
- return a+b
- }
- export let name="井底的蜗牛"
- export default function (){
- console.log("Hello myModule!")
- }
-
- //编译后的结果
- export function sum(a, b) {
- return a + b;
- }
- export let name = "井底的蜗牛";
- export default function () {
- console.log("Hello myModule!");
- }
导入时,不会像commonjs一样,把默认导入的名字给替换,它还是sayHello
- //原文件 index.ts
- import sayHell,{name, sum} from "./myModule";
-
- console.log(sum(1,4))
- console.log(name)
- sayHell()
-
- //编译结果
- import sayHell, { name, sum } from "./myModule";
- console.log(sum(1, 4));
- console.log(name);
- sayHell();
当我们在TS中导入node的一些包时,如import fs from 'fs'
,他可能会报错,提示说fs没有默认导出,
- //原文件 index.ts
- import fs from 'fs'
- fs.readFileSync('./')
编译后的结果是长这样的,因为import fs from 'fs'
这个就相当于commonjs中的默认导入,而fs模块本身导出就是module.exports={}
这种形式 所以编译后就会变成一个对象的default属性,然后去default属性中找readFileSync方法,这当然没有所以报错
- //编译后的文件 index.js
- Object.defineProperty(exports, "__esModule", { value: true });
- const fs_1 = require("fs");
- fs_1.default.readFileSync('./');
如何解决这种报错,有三种方法
import {readFileSync} from 'fs'
这种按需导入的方式,就不会报错了,编译的结果如下- Object.defineProperty(exports, "__esModule", { value: true });
- const fs_1 = require("fs");
- (0, fs_1.readFileSync)('./');
import * as fs from 'fs'
用这种方式进行导入,也可正常使用,当然编译结果和第一种是一样的- Object.defineProperty(exports, "__esModule", { value: true });
- const fs = require("fs");
- fs.readFileSync('./');
"esModuleInterop": true,
进行配置,它的作用就是启用es模块化交互非es模块导出, 然后我们还是使用import fs from 'fs'
,他就不报错了,然后我们看看编译结果 发现多了一个__importDefault
的辅助函数- var __importDefault = (this && this.__importDefault) || function (mod) {
- return (mod && mod.__esModule) ? mod : { "default": mod };
- };
- Object.defineProperty(exports, "__esModule", { value: true });
- const fs_1 = __importDefault(require("fs"));
- fs_1.default.readFileSync('./');
如何在TS中使用commonjs?看下面例子
一般我们是这样用commonjs进行导出的
- //导出原文件文件,myModule.ts
- module.exports = {
- name:'井底的蜗牛',
- sum(a:number,b:number):number{
- return a+b
- }
- }
编译后的结果与原来的是没有变化的
- //编译后的文件 myModule.ts
- module.exports = {
- name: '井底的蜗牛',
- sum(a, b) {
- return a + b;
- }
- };
然而在导入时,会发现使用commonjs导入,const myModule = require("./myModule")
没有类型检查,它检查的结果是any类型,编译后的结果也是一样的
如果想要获取类型检查,最好使用es6的模块化导入导出,当然如果你还是想要使用commonjs进行导入导出,你可以进行如下操作
module.exports ={}
的方式导出,而是使用export={}
的方式进行导出,编译的结果和使用module.exports ={}
的方式是一样的,不同的地方就是使用export={}
有类型检查- //原文件 myModule.ts
- export = {
- name:'井底的蜗牛',
- sum(a:number,b:number):number{
- return a+b
- }
- }
- //编译后的文件 myModule.js
- module.exports = {
- name: '井底的蜗牛',
- sum(a, b) {
- return a + b;
- }
- };
导入的时候也不要使用const myModule = require("./myModule")
方式了,由于你在配置文件中添加了esModuleInterop
为true的配置,
那么你就可以使用es6的方式进行导入import myModule from './myModule'
如果你硬要使用require的方式进行导入,那么你可以这样写import myModule = require("./myModule")
在使用的时候就可以看到其属性的类型了
当然在TS中最好使用ES6的模块化导入导出
模块化解析应该从什么位置寻找模块的呢
TS中,有两种模块解析策略
require("./xxx")
,它先找当前目录下有没有这个文件,如果没有,就看package.json中有没有"main":"xxx.ts"
这个配置,他就会找./xxx
这个文件夹下有没有xxx.ts
这个文件,如果还是没有,就会去找这个文件夹下有没有index.xx
这个文件require("xxx")
,它是去找node_modules目录下当前文件夹有没有该文件,如果没有就一层一层网上找Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。