From c395af656419aa38d5a90bb225b81219592fa186 Mon Sep 17 00:00:00 2001 From: Harris Miller Date: Sun, 14 Aug 2022 15:50:06 -0600 Subject: [PATCH 1/6] add documentation --- packages/typescript/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/typescript/README.md b/packages/typescript/README.md index 6080b3330..11fd09c56 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -214,6 +214,15 @@ typescript({ }); ``` +### `noForceEmit` + +Type: `Boolean`
+Default: `false` + +Earlier version of `@rollup/plugin-typescript` required that the `compilerOptions` `noEmit` and `emitDeclarationOnly` both false to guarantee that source code was fed into the next plugin/output. This is no longer true. This option disables the plugin forcing the values of those options and instead defers to the values set in `tsconfig.json`. + +`noForceEmit` can be very useful if you use with `@rollup/plugin-babel` and `@babel/preset-typescript`. Having `@rollup/plugin-typescript` only do typechecking / declarations with `"emitDeclarationOnly": true` while deferring to `@rollup/plugin-babel` for transpilation can dramatically reduce `rollup` build times for large projects. + ### Typescript compiler options Some of Typescript's [CompilerOptions](https://www.typescriptlang.org/docs/handbook/compiler-options.html) affect how Rollup builds files. @@ -238,6 +247,7 @@ These compiler options are ignored by Rollup: - `noEmitHelpers`, `importHelpers`: The `tslib` helper module always must be used. - `noEmit`, `emitDeclarationOnly`: Typescript needs to emit code for the plugin to work with. + - While this was true for early iterations of `@rollup/plugin-typescript`, it is no longer. To override this behavior, and defer to `tsconfig.json` for these options, see the `noForceEmit` options - `noResolve`: Preventing Typescript from resolving code may break compilation ### Importing CommonJS From ee4304234d182a22e4d3fd5bd85d701c51659a84 Mon Sep 17 00:00:00 2001 From: Harris Miller Date: Sun, 14 Aug 2022 16:05:25 -0600 Subject: [PATCH 2/6] add noForceEmit option and apply in code --- packages/typescript/src/index.ts | 3 ++- packages/typescript/src/options/interfaces.ts | 8 +++++--- packages/typescript/src/options/plugin.ts | 2 ++ packages/typescript/src/options/tsconfig.ts | 12 +++++++++--- packages/typescript/types/index.d.ts | 4 ++++ 5 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/typescript/src/index.ts b/packages/typescript/src/index.ts index c9f828260..f3b263435 100644 --- a/packages/typescript/src/index.ts +++ b/packages/typescript/src/index.ts @@ -25,6 +25,7 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi filterRoot, include, outputToFilesystem, + noForceEmit, transformers, tsconfig, tslib, @@ -34,7 +35,7 @@ export default function typescript(options: RollupTypescriptOptions = {}): Plugi const emittedFiles = new Map(); const watchProgramHelper = new WatchProgramHelper(); - const parsedOptions = parseTypescriptConfig(ts, tsconfig, compilerOptions); + const parsedOptions = parseTypescriptConfig(ts, tsconfig, compilerOptions, noForceEmit); const filter = createFilter(include || ['*.ts+(|x)', '**/*.ts+(|x)'], exclude, { resolve: filterRoot ?? parsedOptions.options.rootDir }); diff --git a/packages/typescript/src/options/interfaces.ts b/packages/typescript/src/options/interfaces.ts index 7a1baab29..618e49339 100644 --- a/packages/typescript/src/options/interfaces.ts +++ b/packages/typescript/src/options/interfaces.ts @@ -13,13 +13,15 @@ export const DEFAULT_COMPILER_OPTIONS: PartialCompilerOptions = { skipLibCheck: true }; +export const OVERRIDABLE_EMIT_COMPILER_OPTIONS: Partial = { + noEmit: false, + emitDeclarationOnly: false +}; + export const FORCED_COMPILER_OPTIONS: Partial = { // Always use tslib noEmitHelpers: true, importHelpers: true, - // Typescript needs to emit the code for us to work with - noEmit: false, - emitDeclarationOnly: false, // Preventing Typescript from resolving code may break compilation noResolve: false }; diff --git a/packages/typescript/src/options/plugin.ts b/packages/typescript/src/options/plugin.ts index a5949f1f1..74e638c9c 100644 --- a/packages/typescript/src/options/plugin.ts +++ b/packages/typescript/src/options/plugin.ts @@ -19,6 +19,7 @@ export const getPluginOptions = (options: RollupTypescriptOptions) => { exclude, include, filterRoot, + noForceEmit, transformers, tsconfig, tslib, @@ -34,6 +35,7 @@ export const getPluginOptions = (options: RollupTypescriptOptions) => { include, exclude, filterRoot, + noForceEmit, tsconfig, compilerOptions: { ...extra, ...compilerOptions } as PartialCompilerOptions, typescript: typescript || defaultTs, diff --git a/packages/typescript/src/options/tsconfig.ts b/packages/typescript/src/options/tsconfig.ts index f6ddbd477..f686add73 100644 --- a/packages/typescript/src/options/tsconfig.ts +++ b/packages/typescript/src/options/tsconfig.ts @@ -21,6 +21,7 @@ import { DEFAULT_COMPILER_OPTIONS, EnumCompilerOptions, FORCED_COMPILER_OPTIONS, + OVERRIDABLE_EMIT_COMPILER_OPTIONS, PartialCompilerOptions } from './interfaces'; import { normalizeCompilerOptions, makePathsAbsolute } from './normalize'; @@ -38,6 +39,10 @@ export interface TypeScriptConfig { compileOnSave?: boolean | undefined; } +function makeForcedCompilerOptions(noForceEmit: boolean) { + return { ...FORCED_COMPILER_OPTIONS, ...(noForceEmit ? OVERRIDABLE_EMIT_COMPILER_OPTIONS : {}) }; +} + /** * Finds the path to the tsconfig file relative to the current working directory. * @param relativePath Relative tsconfig path given by the user. @@ -110,7 +115,8 @@ const configCache = new Map() as import('typescript').Map Date: Sun, 14 Aug 2022 16:18:09 -0600 Subject: [PATCH 3/6] fix that issue with | undefined --- packages/typescript/src/options/plugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typescript/src/options/plugin.ts b/packages/typescript/src/options/plugin.ts index 74e638c9c..30952fdb9 100644 --- a/packages/typescript/src/options/plugin.ts +++ b/packages/typescript/src/options/plugin.ts @@ -35,7 +35,7 @@ export const getPluginOptions = (options: RollupTypescriptOptions) => { include, exclude, filterRoot, - noForceEmit, + noForceEmit: noForceEmit || false, tsconfig, compilerOptions: { ...extra, ...compilerOptions } as PartialCompilerOptions, typescript: typescript || defaultTs, From 11bdaafea9539a3f34e28c8190b03549c745f259 Mon Sep 17 00:00:00 2001 From: Harris Miller Date: Sun, 14 Aug 2022 22:07:28 -0600 Subject: [PATCH 4/6] tests WIP --- .../incremental-single/tsconfig.tsbuildinfo | 12 ++++-- .../noForceEmit/emitDeclarationOnly/main.ts | 3 ++ .../emitDeclarationOnly/tsconfig.json | 7 +++ .../test/fixtures/noForceEmit/noEmit/main.ts | 3 ++ .../fixtures/noForceEmit/noEmit/tsconfig.json | 7 +++ packages/typescript/test/test.js | 43 +++++++++++++++++++ 6 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/main.ts create mode 100644 packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/tsconfig.json create mode 100644 packages/typescript/test/fixtures/noForceEmit/noEmit/main.ts create mode 100644 packages/typescript/test/fixtures/noForceEmit/noEmit/tsconfig.json diff --git a/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo b/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo index 9b9d07b98..c6e190e65 100644 --- a/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo +++ b/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo @@ -391,6 +391,11 @@ "signature": "ef91066d2057cca50511e3af2d4aa54e07913a15f9cee1748f256139318eb413", "affectsGlobalScope": false }, + "../../../../../node_modules/.pnpm/@babel+types@7.14.5/node_modules/@babel/types/lib/index.d.ts": { + "version": "a17ba25a194979a88bfd925e849d76b63f68c4160b69a99c5d723eac5ffddaf0", + "signature": "a17ba25a194979a88bfd925e849d76b63f68c4160b69a99c5d723eac5ffddaf0", + "affectsGlobalScope": false + }, "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts": { "version": "8678956904af215fe917b2df07b6c54f876fa64eb1f8a158e4ff38404cef3ff4", "signature": "8678956904af215fe917b2df07b6c54f876fa64eb1f8a158e4ff38404cef3ff4", @@ -744,15 +749,13 @@ "configFilePath": "./tsconfig.json", "noEmitHelpers": true, "importHelpers": true, - "noEmit": false, - "emitDeclarationOnly": false, "noResolve": false, "sourceMap": true, "inlineSources": true }, "referencedMap": { "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts": [ - "../../../../../node_modules/.pnpm/@babel+types@7.12.1/node_modules/@babel/types/lib/index.d.ts" + "../../../../../node_modules/.pnpm/@babel+types@7.14.5/node_modules/@babel/types/lib/index.d.ts" ], "../../../../../node_modules/.pnpm/@types+babel__core@7.1.10/node_modules/@types/babel__core/index.d.ts": [ "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts", @@ -1154,7 +1157,7 @@ }, "exportedModulesMap": { "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts": [ - "../../../../../node_modules/.pnpm/@babel+types@7.12.1/node_modules/@babel/types/lib/index.d.ts" + "../../../../../node_modules/.pnpm/@babel+types@7.14.5/node_modules/@babel/types/lib/index.d.ts" ], "../../../../../node_modules/.pnpm/@types+babel__core@7.1.10/node_modules/@types/babel__core/index.d.ts": [ "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts", @@ -1557,6 +1560,7 @@ "semanticDiagnosticsPerFile": [ "../../../../../node_modules/.pnpm/@babel+parser@7.12.3/node_modules/@babel/parser/typings/babel-parser.d.ts", "../../../../../node_modules/.pnpm/@babel+types@7.12.1/node_modules/@babel/types/lib/index.d.ts", + "../../../../../node_modules/.pnpm/@babel+types@7.14.5/node_modules/@babel/types/lib/index.d.ts", "../../../../../node_modules/.pnpm/@types+babel__core@7.1.10/node_modules/@types/babel__core/index.d.ts", "../../../../../node_modules/.pnpm/@types+babel__generator@7.6.2/node_modules/@types/babel__generator/index.d.ts", "../../../../../node_modules/.pnpm/@types+babel__template@7.0.3/node_modules/@types/babel__template/index.d.ts", diff --git a/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/main.ts b/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/main.ts new file mode 100644 index 000000000..b460392db --- /dev/null +++ b/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/main.ts @@ -0,0 +1,3 @@ +const answer = 42; + +export { answer }; diff --git a/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/tsconfig.json b/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/tsconfig.json new file mode 100644 index 000000000..e4764f248 --- /dev/null +++ b/packages/typescript/test/fixtures/noForceEmit/emitDeclarationOnly/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "emitDeclarationOnly": true, + "declaration": true, + "outDir": "dist" + } +} diff --git a/packages/typescript/test/fixtures/noForceEmit/noEmit/main.ts b/packages/typescript/test/fixtures/noForceEmit/noEmit/main.ts new file mode 100644 index 000000000..b460392db --- /dev/null +++ b/packages/typescript/test/fixtures/noForceEmit/noEmit/main.ts @@ -0,0 +1,3 @@ +const answer = 42; + +export { answer }; diff --git a/packages/typescript/test/fixtures/noForceEmit/noEmit/tsconfig.json b/packages/typescript/test/fixtures/noForceEmit/noEmit/tsconfig.json new file mode 100644 index 000000000..60714267a --- /dev/null +++ b/packages/typescript/test/fixtures/noForceEmit/noEmit/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "declaration": true, + "noEmit": true, + "outDir": "dist" + } +} diff --git a/packages/typescript/test/test.js b/packages/typescript/test/test.js index 1d2cc0e7a..32ef9c1fe 100644 --- a/packages/typescript/test/test.js +++ b/packages/typescript/test/test.js @@ -1208,3 +1208,46 @@ test.serial('works when code is in src directory', async (t) => { ['index.js', 'index.d.ts'] ); }); + +test.serial('noForceEmit option defers to tsconfig.json for emitDeclarationOnly', async (t) => { + process.chdir('fixtures/noForceEmit/emitDeclarationOnly'); + + const warnings = []; + const bundle = await rollup({ + input: 'main.ts', + plugins: [typescript({ noForceEmit: true })], + onwarn(warning) { + warnings.push(warning); + } + }); + // generate a single output bundle, in which case, declaration files were not correctly emitted + const output = await getCode(bundle, { format: 'esm', file: 'dist/main.js' }, true); + + t.deepEqual( + output.map((out) => out.fileName), + ['main.js', 'main.d.ts'] + ); + t.is(warnings.length, 0); + // TODO test that `main.js` still has typescript in it, since `emitDeclarationOnly` would have skipped ts transpilation +}); + +test.serial('noForceEmit option defers to tsconfig.json for noEmit', async (t) => { + process.chdir('fixtures/noForceEmit/noEmit'); + + const warnings = []; + const bundle = await rollup({ + input: 'main.ts', + plugins: [typescript({ noForceEmit: true })], + onwarn(warning) { + warnings.push(warning); + } + }); + // generate a single output bundle, in which case, declaration files were not correctly emitted + const output = await getCode(bundle, { format: 'esm', file: 'dist/main.js' }, true); + + t.deepEqual( + output.map((out) => out.fileName), + ['main.js'] + ); + t.is(warnings.length, 0); +}); From d8567a0560af5ee91a5f161a459c4b936d33d037 Mon Sep 17 00:00:00 2001 From: Harris Miller Date: Tue, 16 Aug 2022 19:09:36 -0600 Subject: [PATCH 5/6] MR feedback for README --- packages/typescript/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typescript/README.md b/packages/typescript/README.md index 11fd09c56..8200c62af 100644 --- a/packages/typescript/README.md +++ b/packages/typescript/README.md @@ -247,7 +247,7 @@ These compiler options are ignored by Rollup: - `noEmitHelpers`, `importHelpers`: The `tslib` helper module always must be used. - `noEmit`, `emitDeclarationOnly`: Typescript needs to emit code for the plugin to work with. - - While this was true for early iterations of `@rollup/plugin-typescript`, it is no longer. To override this behavior, and defer to `tsconfig.json` for these options, see the `noForceEmit` options + - _Note: While this was true for early iterations of `@rollup/plugin-typescript`, it is no longer. To override this behavior, and defer to `tsconfig.json` for these options, see the [`noForceEmit`](#noForceEmit) option_ - `noResolve`: Preventing Typescript from resolving code may break compilation ### Importing CommonJS From ed231f14c8ca5826c3966cb6dd9ab2a48231e0c7 Mon Sep 17 00:00:00 2001 From: Harris Miller Date: Tue, 16 Aug 2022 19:50:27 -0600 Subject: [PATCH 6/6] fix tests --- packages/typescript/src/options/tsconfig.ts | 2 +- .../incremental-single/tsconfig.tsbuildinfo | 2 + packages/typescript/test/test.js | 42 ++++++++++++++----- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/packages/typescript/src/options/tsconfig.ts b/packages/typescript/src/options/tsconfig.ts index f686add73..52c85eceb 100644 --- a/packages/typescript/src/options/tsconfig.ts +++ b/packages/typescript/src/options/tsconfig.ts @@ -40,7 +40,7 @@ export interface TypeScriptConfig { } function makeForcedCompilerOptions(noForceEmit: boolean) { - return { ...FORCED_COMPILER_OPTIONS, ...(noForceEmit ? OVERRIDABLE_EMIT_COMPILER_OPTIONS : {}) }; + return { ...FORCED_COMPILER_OPTIONS, ...(noForceEmit ? {} : OVERRIDABLE_EMIT_COMPILER_OPTIONS) }; } /** diff --git a/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo b/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo index c6e190e65..32e361706 100644 --- a/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo +++ b/packages/typescript/test/fixtures/incremental-single/tsconfig.tsbuildinfo @@ -750,6 +750,8 @@ "noEmitHelpers": true, "importHelpers": true, "noResolve": false, + "noEmit": false, + "emitDeclarationOnly": false, "sourceMap": true, "inlineSources": true }, diff --git a/packages/typescript/test/test.js b/packages/typescript/test/test.js index 32ef9c1fe..d72fea497 100644 --- a/packages/typescript/test/test.js +++ b/packages/typescript/test/test.js @@ -1210,44 +1210,64 @@ test.serial('works when code is in src directory', async (t) => { }); test.serial('noForceEmit option defers to tsconfig.json for emitDeclarationOnly', async (t) => { - process.chdir('fixtures/noForceEmit/emitDeclarationOnly'); - + const input = 'fixtures/noForceEmit/emitDeclarationOnly/main.ts'; const warnings = []; const bundle = await rollup({ - input: 'main.ts', - plugins: [typescript({ noForceEmit: true })], + input, + plugins: [ + typescript({ + tsconfig: 'fixtures/noForceEmit/emitDeclarationOnly/tsconfig.json', + noForceEmit: true + }) + ], onwarn(warning) { warnings.push(warning); } }); // generate a single output bundle, in which case, declaration files were not correctly emitted - const output = await getCode(bundle, { format: 'esm', file: 'dist/main.js' }, true); + const output = await getCode( + bundle, + { format: 'esm', file: 'fixtures/noForceEmit/emitDeclarationOnly/dist/main.js' }, + true + ); t.deepEqual( output.map((out) => out.fileName), + // original file is passed through, main.d.ts is emitted ['main.js', 'main.d.ts'] ); t.is(warnings.length, 0); - // TODO test that `main.js` still has typescript in it, since `emitDeclarationOnly` would have skipped ts transpilation + // test that NO transpilation happened + const originalCode = fs.readFileSync(path.join(__dirname, input), 'utf8'); + t.is(output[0].code, originalCode); }); test.serial('noForceEmit option defers to tsconfig.json for noEmit', async (t) => { - process.chdir('fixtures/noForceEmit/noEmit'); - + const input = 'fixtures/noForceEmit/noEmit/main.ts'; const warnings = []; const bundle = await rollup({ - input: 'main.ts', - plugins: [typescript({ noForceEmit: true })], + input, + plugins: [ + typescript({ tsconfig: 'fixtures/noForceEmit/noEmit/tsconfig.json', noForceEmit: true }) + ], onwarn(warning) { warnings.push(warning); } }); // generate a single output bundle, in which case, declaration files were not correctly emitted - const output = await getCode(bundle, { format: 'esm', file: 'dist/main.js' }, true); + const output = await getCode( + bundle, + { format: 'esm', file: 'fixtures/noForceEmit/noEmit/dist/main.js' }, + true + ); t.deepEqual( output.map((out) => out.fileName), + // no `main.d.ts`, main.js is passed through ['main.js'] ); t.is(warnings.length, 0); + // test that NO transpilation happened + const originalCode = fs.readFileSync(path.join(__dirname, input), 'utf8'); + t.is(output[0].code, originalCode); });