typescript编译选项对输出目录结构的影响
typescript工程编译后的输出结构之灵活多变一直是个困扰我的难题,这次通过多种试验终于搞清了基本原理:
源目录结构:
app| |dist |src |app.ts |srcjs |lib.js |node_modules |tsconfig.json
如果 js 文件最终“参与”编译,那么输出结构:
app| |dist |src |app.js |srcjs |lib.js
参与的条件为设置了 allowJs
, 而与ts 文件中实际用到 js与否
无关。(注意后文的扩充修正)
如果 js 文件未参与,那么
app| |dist |app.js
以上两种结构,lib.js 相对于 app.js(编译后)的路径都一样,所以只要 app.ts 中是以
1 | require('../srcjs/lib') |
即相对路径的形式来引用 lib,实际运行都能正确引入。
但是,如果参与编译的 ts 目录有多个,必然会在 dist 下形成相应的子目录结构
此时若 allowJs 为 false,那么 lib.js 相对于 app.js 的路径就与源码结构不一样了(多了一级子目录)
需要小心处理
## 对于多 ts 目录的情况
一般会在 tsconfig.include 中设置:
如果没有设,那么默认就是 app 目录内的所有文件,此时 js 文件是否包括就看 allowJs 是否为 true;
如果设置了,那么就只编译指定的目录,此时又有几种特殊情况:
1、如果实际上只有一个 ts 目录内有文件,最终生成的 dist 里就没有子目录结构,而是与那个唯一的 ts 目录直接对应
2、如果 include 中并没有指定 js 目录,那么即使 allowJs 为 true 也不会编译 js,若此时只有一个 ts 目录,也会导致与 1 相同情况
3、即不管什么原因,只要最终生成的 js 文件都属同一子目录,就会导致 dist 下无子目录结构(注:只在没设 rootDir 的前提下成立,下面详解)
## 其它选项的影响
参考:https://www.typescriptlang.org/docs/handbook/compiler-options.html
“sourceRoot”: “./”, /_ Specify the location where debugger should locate TypeScript files instead of source locations. /
“outFile”: “./”, / Concatenate and emit output to single file. /
“outDir”: “./”, / Redirect output structure to the directory. /
“rootDir”: “./”, / Specify the root directory of input files. Use to control the output directory structure with --outDir. /
“rootDirs”: [], / List of root folders whose combined content represents the structure of the project at runtime. _/
sourceRoot 仅仅影响调试器对源码的定位,与编译无关
rootDir 最大的变数
真正决定哪些文件参与编译的是 include,而 rootDir 只起到调节输出目录结构的作用
测试一:如果不为当前目录,有别的用处吗? 设为某一 ts 子目录,此时:
- include 中有其它目录(或未设则默认所有子目录),报错: 编译的文件不在 rootDir 中,但实际编译还是完成了,生成文件以 include 为准
- include 中也只有该目录,如果编译成功的话,在 dist 下生成该目录下所有子目录(不论各子目录是否有文件)
1 | /// <reference types="node" /> |
根据搜索得知这是一个3斜杠
编译指令,起到告知编译器引入类型的作用
参考:https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html
细节:
- 该指令在哪个文件中不重要,只要参与编译的任何一个文件(不管是 ts 还是 node_modules 下面的 js)有这句话就行
- 必须在文件的头部,即所有代码之前才有效
测试二:设(为当前目录)与不设,对 dist 目录却有影响:
上一段提到的第 3 条,仅在 rootDir 不设时生效。若 rootDir=’.’,那么 dist 下一定呈现子目录结构(哪怕只有一个)
测试三:以下目录结构
project |dist |itest |xxx |xx.ts |yyy |yy.ts |src |app.ts |srcjs |lib.js |node_modules |tsconfig.json
设include=['itest/xxx']
若 rootDir不设
: dist 下会直接出现 xx.js,即以输出文件所属最深同根目录
来动态判定,因为只有 xx.ts 被编译,所以直接生成到 dist 下面;如果此时 include 中还有 itest/yyy,那么 dist 下就会有 xxx 和 yyy,而同根目录 itest 被去掉。
若 rootDir=itest
: 显式指定后,无论 yyy 是否参与(include),dist 下都会有 xxx,而不是 xx.js 直接出现;
若rootDir=.
: 也是显式指定,但同根目录
更上了一层,所以哪怕即使只有 xx.js 输出,dist 下也是 itest/xxx/xx.js
rootDirs 可能是最难理解的一个
意义是定义虚拟目录结构
,作用是把不同目录层次下的源文件
“看成”是同一次层次的
但是这个转换仅仅影响编译时
对类型的导入,完全不影响输出目录结构
举例:
project |dist |itest |xxx |xx.ts |yyy |ppp |p.ts |yy.ts |src |app.ts |srcjs |lib.js |node_modules |tsconfig.json
若 xx.ts 中有
1 | import p from './p'; |
按一般设置,这个 p 肯定是找不到的,因为与 xx.ts 不在一个目录下。
但是若设置
1 | rootDirs:['itest/xxx','itest/yyy/ppp'] |
那么编译时
就神奇的通过了,因为编译器被通知这两个目录下的文件可以看作在同一目录里!
但是—— 在 dist 里,p.js 并没有被移到 xxx 下面,xx.js 中对 p 的 require 也并没有被调整! 要想运行时不出错,需要自己去调整输出目录结构!
另外:
1、这里 p 必须是相对路径
2、相对的程度与 rootDirs 中对应,如那边是itest/yyy/ppp
的话这边就./p
,如那边是itest/yyy
则这边就要./ppp/p
,总之凑起来要拼出正确的路径