@build-script/typescript-transformer-dual-package

A TypeScript transformer for (mainly) use with ttypescript that will (semi-)auto create dual package hazard.

Usage no npm install needed!

<script type="module">
  import buildScriptTypescriptTransformerDualPackage from 'https://cdn.skypack.dev/@build-script/typescript-transformer-dual-package';
</script>

README

English

这是个啥子哦

这是一个ttypescript插件:

  • 在 tsc 正常编译文件后,重新编译它,用于生成 commonjs 格式的文件(以.cjs结尾)。
  • 在每个顶级import语句的路径中添加.js(暂不支持修改动态 import 语句)
  • 在 commonjs 格式的文件中,将import.meta.url转换成"file://" + __filename

使用方法

  1. 安装typescriptttypescript,以及这个包
    npm install --save-dev typescript ttypescript @build-script/typescript-transformer-dual-package
    
  2. 在你的tsconfig.json中插入一段:
    {
        "compilerOptions": {
            "module": "esnext", // 必须,可以是老版本(比如es6),但不能是commonjs、systemjs等非ESM目标
            // ... 其他选项
            "plugins": [
                {
                    "transform": " @build-script/typescript-transformer-dual-package",
                    "compilerOptions": {
                        // [可选]
                        // 通常都不需要设置这个,可用于在第二次编译时覆盖父级compilerOptions
                        // 部分选项设置了也无效(例如module)
                    },
                    "verbose": false // 可以设置成true或1 !输出爆炸警告!
                }
            ]
        }
    }
    
  3. 写 TS 的大部分过程都不变,但是需要注意:
    • 别在你自己的代码里用任何一个require,用await import()代替。(使用module::createRequireAPI 的情况除外)
    • 不要在 import 的路径后面加\.(c|m)?js这样的扩展名(比如import "./some-file.js"
  4. 建议:
    • 打开allowSyntheticDefaultImportsesModuleInterop两个选项(在 tsconfig.json 里)
  5. 编译时用ttsc而不是tsc(webpack 等打包工具均支持 ttypescript,具体看他们的文档)
    npm install ttypescript
    ttsc -p path/to/tsconfig.json
    
  6. 在你的package.json里这样写:
    {
        "type": "module",
        "main": "lib/api.cjs",
        // "browser": "lib/api.cjs",
        "module": "lib/api.js",
        // "esnext": "lib/api.js",
        "bin": {
            "some-cli-command": "lib/bin.cjs"
        },
        "exports": {
            ".": {
                "require": "lib/api.cjs",
                "import": "lib/api.js"
            },
            "some-path.js": {
                "require": "lib/some-path.cjs",
                "import": "lib/some-path.js"
            }
        }
    }
    
  7. 如果你的包含有命令行入口(没有就没事了)并且它不是 tsc 编译的输出
    • 将其扩展名改成.cjs

相关信息:

基本原理

  1. tsc/ttsc启动
    1. 它根据 tsconfig 加载这个包
    2. 创建Program对象,初始化包括这个包在内的 transformer
    3. 这个包内复制一个 Program 对象,用于之后编译 cjs。这次的 module 设置为 commonjs,并且添加了一个“内部 transformer”
  2. Programemit被调用(被 webpack、tsc),对每个被编译的文件:
    1. 修改文件中的ImportDeclarationExportDeclaration,给他们添加.js扩展名
    2. 调用之前复制的Programemit,它会重新编译一次,在此过程中“内部 transformer”生效
      1. 修改文件中的ImportDeclarationExportDeclaration,给他们添加.cjs扩展名,并将import.meta.url替换