From 06d9a39cec8254ebab76a81026ab0e64a2f05462 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Wed, 1 Jun 2022 15:59:20 +0200 Subject: [PATCH] feat(jsii): make source map behavior fully configurable (#3558) Instead of enabling declarations maps everywhere as was done in #3521, allow customers to define their desired source-map related configuration in the `jsii.tsc` stanza of `package.json`. This change in stance is motivated by how introduction of declarations map causes broad asset hash changes in consumer code, which effectively breaks many snapshot-based regression tests, and this feature should hence be opt-in. --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- .github/workflows/main.yml | 1 + .../lib-author/configuration/index.md | 8 ++- packages/@jsii/check-node/src/index.test.ts | 6 +-- packages/@scope/jsii-calc-lib/package.json | 3 +- packages/jsii/lib/compiler.ts | 3 -- packages/jsii/lib/project-info.ts | 51 +++++++++++++++++-- packages/jsii/test/compiler.test.ts | 11 +++- packages/jsii/test/deprecated-remover.test.ts | 24 ++++----- 8 files changed, 80 insertions(+), 27 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6401688655..20cb7df8f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,6 +9,7 @@ on: env: DOTNET_NOLOGO: true + NODE_OPTIONS: --max-old-space-size=4096 # This workflows currently has the following jobs: # - build : Builds the source tree as-is diff --git a/gh-pages/content/user-guides/lib-author/configuration/index.md b/gh-pages/content/user-guides/lib-author/configuration/index.md index 43c42f7371..ee16302496 100644 --- a/gh-pages/content/user-guides/lib-author/configuration/index.md +++ b/gh-pages/content/user-guides/lib-author/configuration/index.md @@ -186,8 +186,14 @@ are set in the `jsii.tsc` section of the `package.json` file, but use the same n - `rootDir` - specifies the root directory that contains all of the `.ts` source files. This is used in conjunction with `outDir`, to control the directory structure that gets generated. - `forceConsistentCasingInFileNames` - if `true`, will make the `TypeScript` compiler care about the casing of files - specified in `import` statements. This is helpful if you're developing on a filesystem that is case-insensitive + specified in `import` statements. This is helpful if you're developing on a filesystem that is case-insensitive (Mac/Win), but building/deploying on a filesystem that is case-sensitive (Linux). +- `declarationMap`, `inlineSourceMap`, `inlineSources`, and `sourceMap` allow confifuring the source map generation. + This option can be useful to finely control your local development experience (for example, by enabling + `declarationMap`), or to optimize the emitted code size (by disabling source maps entirely). + + if any of these options is specified, the source map configuration will exactly match what is being provided here + + If none are specified, the default settings will be used: `#!ts { inlineSourceMap: true, inlineSources: true }` + Refer to the [TypeScript compiler options reference][ts-options] for more information about those options. [`tsconfig.json`]: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html diff --git a/packages/@jsii/check-node/src/index.test.ts b/packages/@jsii/check-node/src/index.test.ts index fcb1255fbb..5e5326353e 100644 --- a/packages/@jsii/check-node/src/index.test.ts +++ b/packages/@jsii/check-node/src/index.test.ts @@ -10,10 +10,10 @@ test('tested node releases are correctly registered & supported', () => { }); // This test is there to ensure house-keeping happens when it should. If we are -// testing a given node release, it must not have been EOL for over 30 days. -test('tested node release have not ben EOL for more than 30 days', () => { +// testing a given node release, it must not have been EOL for over 60 days. +test('tested node release have not ben EOL for more than 60 days', () => { const { nodeRelease } = NodeRelease.forThisRuntime(); expect(nodeRelease?.endOfLifeDate?.getTime()).toBeGreaterThan( - Date.now() - 30 * 86_400_000, + Date.now() - 60 * 86_400_000, ); }); diff --git a/packages/@scope/jsii-calc-lib/package.json b/packages/@scope/jsii-calc-lib/package.json index 66f3acb649..a025ea36a2 100644 --- a/packages/@scope/jsii-calc-lib/package.json +++ b/packages/@scope/jsii-calc-lib/package.json @@ -69,7 +69,8 @@ } }, "tsc": { - "outDir": "build" + "outDir": "build", + "sourceMap": false }, "versionFormat": "short", "metadata": { diff --git a/packages/jsii/lib/compiler.ts b/packages/jsii/lib/compiler.ts index 54b6f534b8..ec3b3c4a09 100644 --- a/packages/jsii/lib/compiler.ts +++ b/packages/jsii/lib/compiler.ts @@ -16,11 +16,8 @@ const BASE_COMPILER_OPTIONS: ts.CompilerOptions = { alwaysStrict: true, charset: 'utf8', declaration: true, - declarationMap: true, experimentalDecorators: true, incremental: true, - inlineSourceMap: true, - inlineSources: true, lib: ['lib.es2019.d.ts'], module: ts.ModuleKind.CommonJS, newLine: ts.NewLineKind.LineFeed, diff --git a/packages/jsii/lib/project-info.ts b/packages/jsii/lib/project-info.ts index 39f063be7d..a514d2c088 100644 --- a/packages/jsii/lib/project-info.ts +++ b/packages/jsii/lib/project-info.ts @@ -13,11 +13,21 @@ const spdx: Set = require('spdx-license-list/simple'); const LOG = log4js.getLogger('jsii/package-info'); -export interface TSCompilerOptions { - readonly outDir?: string; - readonly rootDir?: string; - readonly forceConsistentCasingInFileNames?: boolean; -} +export type TSCompilerOptions = Partial< + Pick< + ts.CompilerOptions, + // Directory preferences + | 'outDir' + | 'rootDir' + // Style preferences + | 'forceConsistentCasingInFileNames' + // Source map preferences + | 'declarationMap' + | 'inlineSourceMap' + | 'inlineSources' + | 'sourceMap' + > +>; export interface ProjectInfo { readonly projectRoot: string; @@ -207,6 +217,9 @@ export function loadProjectInfo(projectRoot: string): ProjectInfoResult { tsc: { outDir: pkg.jsii?.tsc?.outDir, rootDir: pkg.jsii?.tsc?.rootDir, + forceConsistentCasingInFileNames: + pkg.jsii?.tsc?.forceConsistentCasingInFileNames, + ..._sourceMapPreferences(pkg.jsii?.tsc), }, bin: pkg.bin, exports: pkg.exports, @@ -228,6 +241,34 @@ function _guessRepositoryType(url: string): string { ); } +function _sourceMapPreferences({ + declarationMap, + inlineSourceMap, + inlineSources, + sourceMap, +}: TSCompilerOptions = {}) { + // If none of the options are specified, use the default configuration from jsii <= 1.58.0, which + // means inline source maps with embedded source information. + if ( + declarationMap == null && + inlineSourceMap == null && + inlineSources == null && + sourceMap == null + ) { + declarationMap = false; + inlineSourceMap = true; + inlineSources = true; + sourceMap = undefined; + } + + return { + declarationMap, + inlineSourceMap, + inlineSources, + sourceMap, + }; +} + interface DependencyInfo { readonly assembly: spec.Assembly; readonly resolvedDependencies: Record; diff --git a/packages/jsii/test/compiler.test.ts b/packages/jsii/test/compiler.test.ts index 2e9a6460b1..e8a3131c35 100644 --- a/packages/jsii/test/compiler.test.ts +++ b/packages/jsii/test/compiler.test.ts @@ -149,7 +149,7 @@ describe(Compiler, () => { } }); - test('emits declaration map', () => { + test('emits declaration map when feature is enabled', () => { const sourceDir = mkdtempSync(join(tmpdir(), 'jsii-tmpdir')); try { @@ -158,6 +158,9 @@ describe(Compiler, () => { const compiler = new Compiler({ projectInfo: { ..._makeProjectInfo(sourceDir, 'index.d.ts'), + tsc: { + declarationMap: true, + }, }, generateTypeScriptConfig: 'tsconfig.jsii.json', }); @@ -191,6 +194,11 @@ function _makeProjectInfo(sourceDir: string, types: string): ProjectInfo { bundleDependencies: {}, targets: {}, excludeTypescript: [], + tsc: { + // NOTE: these are the default values jsii uses when none are provided in package.json. + inlineSourceMap: true, + inlineSources: true, + }, }; } @@ -203,7 +211,6 @@ function expectedTypeScriptConfig() { charset: 'utf8', composite: false, declaration: true, - declarationMap: true, experimentalDecorators: true, incremental: true, inlineSourceMap: true, diff --git a/packages/jsii/test/deprecated-remover.test.ts b/packages/jsii/test/deprecated-remover.test.ts index 5c651f9cb7..920d228384 100644 --- a/packages/jsii/test/deprecated-remover.test.ts +++ b/packages/jsii/test/deprecated-remover.test.ts @@ -113,12 +113,12 @@ test('produces correct output', () => { export * from './retained'; export * from './enums'; export { GrandChild, Retained } from './mixed'; - //# sourceMappingURL=index.d.ts.map////////////////// + ////////////////// /////////////////////// /// deprecated.d.ts /// - //# sourceMappingURL=deprecated.d.ts.map/////////////////////// + /////////////////////// ///////////////////// @@ -127,7 +127,7 @@ test('produces correct output', () => { } export declare class RetainedClass { } - //# sourceMappingURL=retained.d.ts.map///////////////////// + ///////////////////// ////////////////// @@ -135,7 +135,7 @@ test('produces correct output', () => { export declare enum SomeEnum { VALUE_RETAINED = 0 } - //# sourceMappingURL=enums.d.ts.map////////////////// + ////////////////// ////////////////// @@ -148,7 +148,7 @@ test('produces correct output', () => { export declare class GrandChild extends Retained implements retained_1.IRetainedInterface { retainedMethod(): void; } - //# sourceMappingURL=mixed.d.ts.map////////////////// + ////////////////// " `); }); @@ -177,12 +177,12 @@ test('cross-file deprecated heritage', () => { import './deprecated'; export interface INotDeprecated { } - //# sourceMappingURL=index.d.ts.map////////////////// + ////////////////// /////////////////////// /// deprecated.d.ts /// - //# sourceMappingURL=deprecated.d.ts.map/////////////////////// + /////////////////////// " `); }); @@ -452,7 +452,7 @@ describe('stripDeprecatedAllowList', () => { export * from './retained'; export * from './enums'; export { Deprecated, GrandChild, Retained } from './mixed'; - //# sourceMappingURL=index.d.ts.map////////////////// + ////////////////// /////////////////////// @@ -460,7 +460,7 @@ describe('stripDeprecatedAllowList', () => { /** @deprecated stripped */ export declare class DeprecatedClass { } - //# sourceMappingURL=deprecated.d.ts.map/////////////////////// + /////////////////////// ///////////////////// @@ -469,7 +469,7 @@ describe('stripDeprecatedAllowList', () => { } export declare class RetainedClass { } - //# sourceMappingURL=retained.d.ts.map///////////////////// + ///////////////////// ////////////////// @@ -482,7 +482,7 @@ describe('stripDeprecatedAllowList', () => { VALUE_ONE = 0, VALUE_TWO = 1 } - //# sourceMappingURL=enums.d.ts.map////////////////// + ////////////////// ////////////////// @@ -499,7 +499,7 @@ describe('stripDeprecatedAllowList', () => { export declare class GrandChild extends Deprecated { retainedMethod(): void; } - //# sourceMappingURL=mixed.d.ts.map////////////////// + ////////////////// " `); });