TypeScript生成ES6的JS

TypeScript生成ES6的JS

我在使用TypeScript过程中有一个疑问,编写的是现代化的js可以用上:在TSconfig.json中

{
  "compilerOptions": {
    "target": "ES6",
    "module": "ES6", 
  }
}

TS代码

// main.ts
import {add, sub} from './mod1';

let a = 10;
const b= 20;
let c = add(a, b);
console.log(c)

let d = sub(b, a);
console.log(d)

// mod1.ts
const sub = function(a:number, b:number):number {
  return a - b;
}

const add = function(a:number, b:number):number {
  return a+b;
}
export { sub ,add };

生成出的ES6的JS是

// main.js
import { add, sub } from './mod1';
let a = 10;
const b = 20;
let c = add(a, b);
console.log(c);
let d = sub(b, a);
console.log(d);

// mod1.js
const sub = function (a, b) {
    return a - b;
};
const add = function (a, b) {
    return a + b;
};
export { sub, add };

可以看出两者几乎是一样的。此时我们执行tsc && node ./dist/main.js时会发现无法执行,提示如下错误:

node:internal/errors:484
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/xxxx/dist/mod1' imported from /Users/pengxu/Work/Code/hello/hello/dist/main.js
    at new NodeError (node:internal/errors:393:5)
    at finalizeResolution (node:internal/modules/esm/resolve:305:11)
    at moduleResolve (node:internal/modules/esm/resolve:866:10)
    at defaultResolve (node:internal/modules/esm/resolve:1074:11)
    at nextResolve (node:internal/modules/esm/loader:163:28)
    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:425:18)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36) {
  code: 'ERR_MODULE_NOT_FOUND'
}

这是什么原因呢?经过研究发现,typescript的import与js的import是不同的:

ts的import不需要完整的文件名:import {add, sub} from ‘./mod1’;

es6的js的需要完整的文件名:import { add, sub } from ‘./mod1.js’;

经过修改后可以运行了。

但是tsc生成的文件不可能一个个的去修改吧。那怎么办呢?又经过研究发现,node有一个选项是允许不带后缀名import的:

node --experimental-specifier-resolution=node ./dist/main.js

其中–experimental-specifier-resolution=node是node的一个实验性选项,开启后执行时会提示一个警告

(node:51193) ExperimentalWarning: The Node.js specifier resolution flag is experimental. It could change or be removed at any time.

吐槽:也许后面的nodejs版本就会不再显示这个警告了;也许后面的nodejs版本不允许这么干了,鬼知道。我想这就是为什么都node18代了,网上的教程还是在教怎么写require,用es5的方式写代码。nodejs本身对module的加载方式太乱了。兼容性太差,坑太多。

加上了这个选项后再执行,发现报这个错误:

(node:51193) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
import { add, sub } from './mod1';
^^^^^^
SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:360:18)
    at wrapSafe (node:internal/modules/cjs/loader:1048:15)
    at Module._compile (node:internal/modules/cjs/loader:1083:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1173:10)
    at Module.load (node:internal/modules/cjs/loader:997:32)
    at Module._load (node:internal/modules/cjs/loader:838:12)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:170:29)
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:527:24)

这个问题的原因是一直以来NODEJS都是用CommonJS的方式(就是require(‘xxxx’)和module.expores={})这种方式导入导出模块。这种方式是同步的,顺序执行的。而es6里的import的区别就大了(根本就是两套逻辑)import是异步的,预加载的。在nodejs进化的历史长河中,花了很多很多年,都没有统一这两种加载方式,历史包袱太重。(后来就有了Deno,这是另一个话题)导致了一代代教程教出来的的程序员前赴后继的写了require。(import可以使用require)。但是就在这个问题还没有搞定的时候,typescript又降维打入进来,我看到很多前端或全栈小哥,在三套标准(commonjs ,es6, ts)之前迷离。写着或机械的,或玄学代码。

扯远了,说回来以上错误的处理方法很简单,在package.json里把type设为module,这是nodejs的配置,如果不加这个时在nodejs遇到.js.cjs文件时会使用CommonJS方式,如果遇到.mjs时用ES6 import加载。(这样就需要在文件扩展名层面上确定是哪种,貌似没有哪个语言是这样的,历史的坑)。还有一种方便的方法就是在package.json中使用type来指定用commonjs还是module方式来处理所有的js文件。

改造后的package.json如下:

// package.json
{
  "main": "./dist/main.js",
  "type": "module",
  "scripts": {
    "dev": "tsc && node --experimental-specifier-resolution=node .",
  }
}

此时就可以正常执行了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值