Closed BitPatty closed 2 years ago
This is a new feature in 0.33.0
, supporting emitDeclarationOnly
. Previously, this tsconfig
option was entirely ignored.
Per the log you provided, it states "rpt2: emitDeclarationOnly enabled, not transforming TS"
. As such, you need another plugin to transform TS to JS when using emitDeclarationOnly
.
Per the docs, this feature is meant to be used together with another plugin, such as @rollup/plugin-babel
, rollup-plugin-esbuild
, rollup-plugin-swc
, etc.
With this use-case, you have rpt2 use the TS compiler to type-check and create declarations, while another plugin does the TS -> JS transform.
Per the release notes, this was implemented in #366 to support the highly requested #268.
As such, this is not a bug, but very much intended behavior.
If you want to keep emitDeclarationOnly
in your tsconfig
for tsc
, but still want rpt2 to do TS -> JS transformation, please use tsconfigOverride
to reset emitDeclarationOnly
to false
for rpt2.
Per the log you provided, it states "rpt2: emitDeclarationOnly enabled, not transforming TS". As such, you need another plugin to transform TS to JS when using emitDeclarationOnly.
Hope I don't misunderstand: What if I only want to emit declarations and not transpile TS at all?
While it did work before and warn about an empty chunk being generated, it still did emit the declaration as expected. And though tsc
itself could be used to build the declaration, the rpt2 simplified the process up until now when using multiple build targets.
While it did work before and warn about an empty chunk being generated, it still did emit the declaration as expected.
Oh. I didn't realize that anyone actually wanted an empty chunk. #268 showed that most folks were pretty confused by the resulting empty chunk. But I guess everyone's got their own workflow š
And though
tsc
itself could be used to build the declaration, the rpt2 simplified the process up until now when using multiple build targets.
Any chance you could provide a small example of where rpt2 simplifies the process vs. using tsc
for multi-build with only declarations? I think I'm missing a detail here, so an example would be great to wrap my head around.
What if I only want to emit declarations and not transpile TS at all?
So this is still possible in 0.33.0
in a slightly hacky way. As long as your TS files are in your tsconfig
include
, rpt2 will still emit their declarations, even if they're not directly part of the Rollup bundle (because that's how tsc
works as well).
So what you could do is use an empty file for Rollup's ~output.file
~ EDIT: woops, I meant input
, which will result in the same behavior as an empty chunk, and then rpt2 will still emit declarations for anything in your tsconfig
include
.
Does that satisfy your use-case? It's a bit hacky, but I do think the intent is a little more clear that way (e.g. empty file -> empty chunk). Most people seemed to have been pretty confused by the empty chunk behavior before and that didn't seem intuitive to them.
Any chance you could provide a small example of where rpt2 simplifies the process vs. using tsc for multi-build with only declarations? I think I'm missing a detail here, so an example would be great to wrap my head around.
In some libraries which I cross build to ESM and CJS I use a split rollup configuration to generate the individual outputs with the same tsconfig
. Essentially only emitting the declaration once into /types
, generating the following output structure:
The configuration boils down to something like this: https://stackblitz.com/edit/rpt2-repro-e2gczu?file=rollup.config.js, i.e:
rollup.config.js
(Full configuration: https://github.com/BitPatty/ts-library-template/blob/2a14eb539eaa6af659467cca5595972e229fa288/rollup.config.js)
So what you could do is use an empty file for Rollup's output.file, which will result in the same behavior as an empty chunk, and then rpt2 will still emit declarations for anything in your tsconfig include.
In my case I already have the declaration file as output.file
, so not sure how/if this would work.
It's a bit hacky, but I do think the intent is a little more clear that way
Not sure if my current solution would be considered hacky as well :)
Of course I could also emit the declaration with both the ESM and the CJS output or copy back the types in a later step, but I figured it'd be nicer to just have the declaration be available at one place and rpt2 made it quite easy to set up this target structure without any extra configuration.
In my case I already have the declaration file as
output.file
, so not sure how/if this would work.
Oh woops, my bad, I meant the input
. Point the input
to an empty file.
(I happened to have been changing a Rollup config at the same time, so I screwed that up, sorry! Of course, the output.file
doesn't exist yet).
rollup.config.js
Thanks for providing a detailed example, that made it much easier to understand! There are in fact other alternatives to achieve this (which was much easier to see at-a-glance with an example!).
A commonly used one by rpt2 users is to set useTsconfigDeclarationDir: true
and declarationDir: './dist/types'
. For instance:
// rollup.config.js
import typescript from 'rollup-plugin-typescript2';
export default [{
input: './src/index.ts',
output: [{
file: './dist/esm/index.js',
format: 'esm',
exports: 'named',
sourcemap: true,
}, {
file: './dist/cjs/index.js',
format: 'cjs',
exports: 'named',
sourcemap: true,
}],
plugins: [
typescript({
verbosity: 3,
clean: true,
useTsconfigDeclarationDir: true,
tsconfigOverride: {
compilerOptions: {
declarationDir: './dist/types',
},
},
}),
],
}];
Note that I'm also using Rollup's multi-output feature here for ESM + CJS, which should optimize your build a bit too, since Rollup won't need to analyze the input a second time around or re-run any input plugins.
The caveat with useTsconfigDeclarationDir
is that other plugins that process declarations won't work (it writes directly to the declarationDir
, bypassing Rollup's emit phase), but it doesn't seem like you need that in your case anyway. And it seems that the vast majority of users are okay with that caveat/trade-off as well, so I think I can safely recommend that option.
Thanks a lot for your time and the hint regarding the useTsconfigDeclarationDir
option. With that configuration it works again (and better) as before :+1:
Troubleshooting
Does
tsc
have the same output? If so, please explain why this is incorrect behaviorNo
Does your Rollup plugin order match this plugin's compatibility? If not, please elaborate
Yes
Can you create a minimal example that reproduces this behavior? Preferably, use this environment for your reproduction
https://stackblitz.com/edit/rpt2-repro-1kadjh?file=package.json
What happens and why it is incorrect
The build crashes if
emitDeclarationOnly
is set totrue
in overrides or tsconfig.tsc
produces the correct output. Used to work until v0.33.0.Environment
Versions
```js import typescript from 'rollup-plugin-typescript2'; export default { input: './src/index.ts', output: { file: './dist/index.ts', format: 'esm', exports: 'named', }, plugins: [ typescript({ verbosity: 3, clean: true, }), ], }; ```
:rollup.config.js
```json5 { // https://github.com/agilgur5/tsconfig "extends": "@agilgur5/tsconfig/src/tsconfig.library.json", // exclude node_modules (the default), dist dir, coverage dir, and example for now "exclude": ["node_modules/", "dist/", "coverage/", "example/"], // all TS files in the src/ dir "include": ["src/**/*"], // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs "compilerOptions": { // output to dist/ dir "outDir": "./dist/", // match output dir to input dir. e.g. dist/index instead of dist/src/index "rootDir": "./src", "emitDeclarationOnly": true } } ```
:tsconfig.json
```json { "name": "rpt2-repro", "version": "0.0.0", "scripts": { "clean": "rm -rf dist/", "build": "rollup -c", "tsc": "tsc" }, "devDependencies": { "@agilgur5/tsconfig": "^0.0.2", "rollup": "^2.75.6", "rollup-plugin-typescript2": "^0.33.0", "typescript": "^4.7.3" } } ```
:package.json
```text ./src/index.ts ā ./dist/index.ts... rpt2: built-in options overrides: { "noEmitHelpers": false, "importHelpers": true, "noResolve": false, "noEmit": false, "noEmitOnError": false, "inlineSourceMap": false, "outDir": "/home/projects/rpt2-repro-1kadjh/node_modules/.cache/rollup-plugin-typescript2/placeholder", "moduleResolution": 2, "allowNonTsExtensions": true, "module": 5 } rpt2: parsed tsconfig: { "options": { "strict": true, "allowUnusedLabels": false, "allowUnreachableCode": false, "exactOptionalPropertyTypes": true, "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, "noPropertyAccessFromIndexSignature": true, "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, "importsNotUsedAsValues": 2, "checkJs": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "outDir": "/home/projects/rpt2-repro-1kadjh/node_modules/.cache/rollup-plugin-typescript2/placeholder", "sourceMap": true, "moduleResolution": 2, "resolveJsonModule": true, "jsx": 2, "noEmit": false, "declaration": true, "declarationMap": true, "rootDir": "/home/projects/rpt2-repro-1kadjh/src", "emitDeclarationOnly": true, "configFilePath": "/home/projects/rpt2-repro-1kadjh/tsconfig.json", "noEmitHelpers": false, "importHelpers": true, "noResolve": false, "noEmitOnError": false, "inlineSourceMap": false, "allowNonTsExtensions": true, "module": 5 }, "fileNames": [ "/home/projects/rpt2-repro-1kadjh/src/index.ts" ], "typeAcquisition": { "enable": false, "include": [], "exclude": [] }, "raw": { "extends": "@agilgur5/tsconfig/src/tsconfig.library.json", "exclude": [ "node_modules/", "dist/", "coverage/", "example/" ], "include": [ "src/**/*" ], "compilerOptions": { "outDir": "./dist/", "rootDir": "./src", "emitDeclarationOnly": true }, "compileOnSave": false }, "errors": [], "wildcardDirectories": { "/home/projects/rpt2-repro-1kadjh/src": 1 }, "compileOnSave": false } rpt2: typescript version: 4.7.3 rpt2: tslib version: 2.4.0 rpt2: rollup version: 2.75.6 rpt2: rollup-plugin-typescript2 version: 0.33.0 rpt2: plugin options: { "check": true, "verbosity": 3, "clean": true, "cacheRoot": "/home/projects/rpt2-repro-1kadjh/node_modules/.cache/rollup-plugin-typescript2", "include": [ "*.ts+(|x)", "**/*.ts+(|x)" ], "exclude": [ "*.d.ts", "**/*.d.ts" ], "abortOnError": true, "rollupCommonJSResolveHack": false, "useTsconfigDeclarationDir": false, "tsconfigOverride": {}, "transformers": [], "tsconfigDefaults": {}, "objectHashIgnoreUnknownHack": false, "cwd": "/home/projects/rpt2-repro-1kadjh", "typescript": "version 4.7.3" } rpt2: rollup config: { "external": [], "input": "./src/index.ts", "plugins": [ { "name": "rpt2" }, { "name": "stdin" } ], "output": [ { "exports": "named", "file": "./dist/index.ts", "format": "esm", "plugins": [] } ] } rpt2: tsconfig path: /home/projects/rpt2-repro-1kadjh/tsconfig.json rpt2: included: [ "*.ts+(|x)", "**/*.ts+(|x)" ] rpt2: excluded: [ "*.d.ts", "**/*.d.ts" ] rpt2: transpiling '/home/projects/rpt2-repro-1kadjh/src/index.ts' rpt2: generated declarations for '/home/projects/rpt2-repro-1kadjh/src/index.ts' rpt2: emitDeclarationOnly enabled, not transforming TS' [!] (plugin rpt2) Error: Unexpected token (Note that you need plugins to import files that are not JavaScript) src/index.ts (4:29) 2: // run `npm run tsc` in the terminal to type-check this file with tsc 3: 4: export default function sum(a: number, b: number) { ^ 5: return a + b; 6: } at error (/home/projects/rpt2-repro-1kadjh/node_modules/rollup/dist/shared/rollup.js:198:30) at Module.error (/home/projects/rpt2-repro-1kadjh/node_modules/rollup/dist/shared/rollup.js:12553:16) at Module.tryParse (/home/projects/rpt2-repro-1kadjh/node_modules/rollup/dist/shared/rollup.js:12930:25) at Module.setSource (/home/projects/rpt2-repro-1kadjh/node_modules/rollup/dist/shared/rollup.js:12835:24) at ModuleLoader.addModuleSource (/home/projects/rpt2-repro-1kadjh/node_modules/rollup/dist/shared/rollup.js:22309:20) ```plugin output with verbosity 3
: