From c9be344e7ffc7dbfbab773904dd807f5a6416816 Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Mon, 24 Apr 2023 18:23:29 -0400 Subject: [PATCH 1/3] chore: stop modifying user tsconfig Signed-off-by: Logan McAnsh --- packages/remix-dev/config.ts | 5 - .../config/write-tsconfig-defaults.ts | 173 ------------------ 2 files changed, 178 deletions(-) delete mode 100644 packages/remix-dev/config/write-tsconfig-defaults.ts diff --git a/packages/remix-dev/config.ts b/packages/remix-dev/config.ts index af7d0455bc2..e0fb7ad61cb 100644 --- a/packages/remix-dev/config.ts +++ b/packages/remix-dev/config.ts @@ -10,7 +10,6 @@ import type { RouteManifest, DefineRoutesFunction } from "./config/routes"; import { defineRoutes } from "./config/routes"; import { defineConventionalRoutes } from "./config/routesConvention"; import { ServerMode, isValidServerMode } from "./config/serverModes"; -import { writeConfigDefaults } from "./config/write-tsconfig-defaults"; import { serverBuildVirtualModule } from "./compiler/server/virtualModules"; import { flatRoutes } from "./config/flat-routes"; import { detectPackageManager } from "./cli/detectPackageManager"; @@ -731,10 +730,6 @@ export async function readConfig( tsconfigPath = rootJsConfig; } - if (tsconfigPath) { - writeConfigDefaults(tsconfigPath); - } - let future: FutureConfig = { unstable_dev: appConfig.future?.unstable_dev ?? false, unstable_postcss: appConfig.future?.unstable_postcss === true, diff --git a/packages/remix-dev/config/write-tsconfig-defaults.ts b/packages/remix-dev/config/write-tsconfig-defaults.ts deleted file mode 100644 index f7fdc9d9ad6..00000000000 --- a/packages/remix-dev/config/write-tsconfig-defaults.ts +++ /dev/null @@ -1,173 +0,0 @@ -import * as path from "path"; -import fse from "fs-extra"; -import type { TsConfigJson } from "type-fest"; -import prettier from "prettier"; -import { loadTsconfig } from "tsconfig-paths/lib/tsconfig-loader"; -import JSON5 from "json5"; - -import * as colors from "../colors"; - -// These are suggested values and will be set when not present in the -// tsconfig.json -let suggestedCompilerOptions: TsConfigJson.CompilerOptions = { - allowJs: true, - forceConsistentCasingInFileNames: true, - lib: ["DOM", "DOM.Iterable", "ES2019"], - strict: true, - target: "ES2019", -}; - -// These values are required and cannot be changed by the user -// Keep this in sync with esbuild -let requiredCompilerOptions: TsConfigJson.CompilerOptions = { - esModuleInterop: true, - isolatedModules: true, - jsx: "react-jsx", - noEmit: true, - resolveJsonModule: true, -}; - -// taken from https://github.com/sindresorhus/ts-extras/blob/781044f0412ec4a4224a1b9abce5ff0eacee3e72/source/object-keys.ts -type ObjectKeys = `${Exclude}`; -function objectKeys(value: Type): Array> { - return Object.keys(value) as Array>; -} - -export function writeConfigDefaults(configPath: string) { - // check files exist - if (!fse.existsSync(configPath)) return; - - // this will be the *full* tsconfig.json with any extensions deeply merged - let fullConfig = loadTsconfig(configPath) as TsConfigJson | undefined; - // this will be the user's actual tsconfig file - let configContents = fse.readFileSync(configPath, "utf8"); - - let config: TsConfigJson | undefined; - try { - config = JSON5.parse(configContents); - } catch (error: unknown) {} - - if (!fullConfig || !config) { - // how did we get here? we validated a tsconfig existed in the first place - console.warn( - "This should never happen, please open an issue with a reproduction https://github.com/remix-run/remix/issues/new" - ); - return; - } - - let configType = path.basename(configPath) as - | "jsconfig.json" - | "tsconfig.json"; - - // sanity checks to make sure we can write the compilerOptions - if (!fullConfig.compilerOptions) fullConfig.compilerOptions = {}; - if (!config.compilerOptions) config.compilerOptions = {}; - - let suggestedChanges = []; - let requiredChanges = []; - - if (!("include" in fullConfig)) { - if (configType === "jsconfig.json") { - config.include = ["**/*.js", "**/*.jsx"]; - suggestedChanges.push( - colors.blue("include") + - " was set to " + - colors.bold(`['**/*.js', '**/*.jsx']`) - ); - } else { - config.include = ["remix.env.d.ts", "**/*.ts", "**/*.tsx"]; - suggestedChanges.push( - colors.blue("include") + - " was set to " + - colors.bold(`['remix.env.d.ts', '**/*.ts', '**/*.tsx']`) - ); - } - } - // TODO: check for user's typescript version and only add baseUrl if < 4.1 - if (!("baseUrl" in fullConfig.compilerOptions)) { - let baseUrl = path.relative(process.cwd(), path.dirname(configPath)) || "."; - config.compilerOptions.baseUrl = baseUrl; - requiredChanges.push( - colors.blue("compilerOptions.baseUrl") + - " was set to " + - colors.bold(`'${baseUrl}'`) - ); - } - for (let key of objectKeys(suggestedCompilerOptions)) { - if (!(key in fullConfig.compilerOptions)) { - config.compilerOptions[key] = suggestedCompilerOptions[key] as any; - suggestedChanges.push( - colors.blue("compilerOptions." + key) + - " was set to " + - colors.bold(`'${suggestedCompilerOptions[key]}'`) - ); - } - } - - for (let key of objectKeys(requiredCompilerOptions)) { - if (fullConfig.compilerOptions[key] !== requiredCompilerOptions[key]) { - config.compilerOptions[key] = requiredCompilerOptions[key] as any; - requiredChanges.push( - colors.blue("compilerOptions." + key) + - " was set to " + - colors.bold(`'${requiredCompilerOptions[key]}'`) - ); - } - } - - if (typeof fullConfig.compilerOptions.moduleResolution === "undefined") { - fullConfig.compilerOptions.moduleResolution = "node"; - config.compilerOptions.moduleResolution = "node"; - requiredChanges.push( - colors.blue("compilerOptions.moduleResolution") + - " was set to " + - colors.bold(`'node'`) - ); - } - - if ( - !["node", "node16", "nodenext", "bundler"].includes( - fullConfig.compilerOptions.moduleResolution.toLowerCase() - ) - ) { - config.compilerOptions.moduleResolution = "node"; - - requiredChanges.push( - colors.blue("compilerOptions.moduleResolution") + - " was set to " + - colors.bold(`'node'`) - ); - } - - if (suggestedChanges.length > 0 || requiredChanges.length > 0) { - fse.writeFileSync( - configPath, - prettier.format(JSON.stringify(config, null, 2), { - parser: "json", - }) - ); - } - if (suggestedChanges.length > 0) { - console.log( - `The following suggested values were added to your ${colors.blue( - `"${configType}"` - )}. These values ${colors.bold( - "can be changed" - )} to fit your project's needs:\n` - ); - - suggestedChanges.forEach((change) => console.log(`\t- ${change}`)); - console.log(""); - } - - if (requiredChanges.length > 0) { - console.log( - `The following ${colors.bold( - "mandatory changes" - )} were made to your ${colors.blue(configType)}:\n` - ); - - requiredChanges.forEach((change) => console.log(`\t- ${change}`)); - console.log(""); - } -} From f9322784a727f707d480fad84e99180c750c53bc Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Tue, 25 Apr 2023 13:36:35 -0400 Subject: [PATCH 2/3] chore: delete obsolete test Signed-off-by: Logan McAnsh --- integration/tsconfig-test.ts | 169 ----------------------------------- 1 file changed, 169 deletions(-) delete mode 100644 integration/tsconfig-test.ts diff --git a/integration/tsconfig-test.ts b/integration/tsconfig-test.ts deleted file mode 100644 index 5c079a1e752..00000000000 --- a/integration/tsconfig-test.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { test, expect } from "@playwright/test"; -import fse from "fs-extra"; -import path from "path"; -import JSON5 from "json5"; -import type { TsConfigJson } from "type-fest"; - -import { createFixture, json } from "./helpers/create-fixture"; - -async function getTsConfig( - projectDir: string, - configType: "tsconfig.json" | "jsconfig.json" = "tsconfig.json" -) { - let configPath = path.join(projectDir, configType); - let config = await fse.readFile(configPath, "utf8"); - return JSON5.parse(config); -} - -// Omit non JSON-serializable things we don't need -type SerializableTsConfigJson = Omit< - TsConfigJson, - "compilerOptions" | "references" | "typeAcquisition" | "watchOptions" -> & { - compilerOptions: Omit; -}; -// this is the default tsconfig.json that is shipped with `create-remix` templates -const DEFAULT_CONFIG: SerializableTsConfigJson = { - include: ["remix.env.d.ts", "**/*.ts", "**/*.tsx"], - compilerOptions: { - allowJs: true, - esModuleInterop: true, - forceConsistentCasingInFileNames: true, - isolatedModules: true, - jsx: "react-jsx", - lib: ["DOM", "DOM.Iterable", "ES2019"], - moduleResolution: "node", - noEmit: true, - resolveJsonModule: true, - strict: true, - target: "ES2019", - baseUrl: ".", - }, -}; - -// besides baseUrl, due to an upstream issue in tsconfig-paths -// https://github.com/dividab/tsconfig-paths/pull/208 -test("should output default tsconfig if file is empty", async () => { - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { - "tsconfig.json": json({ compilerOptions: { baseUrl: "." } }), - }, - }); - - let tsconfig = await getTsConfig(fixture.projectDir); - expect(tsconfig).toEqual(DEFAULT_CONFIG); -}); - -test("should add/update mandatory config", async () => { - let config = { - ...DEFAULT_CONFIG, - compilerOptions: { - ...DEFAULT_CONFIG.compilerOptions, - isolatedModules: false, // true is required by esbuild - }, - }; - delete config.compilerOptions.moduleResolution; // this is required by esbuild - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { "tsconfig.json": json(config) }, - }); - - let tsconfig = await getTsConfig(fixture.projectDir); - expect(tsconfig).toEqual(DEFAULT_CONFIG); -}); - -test("shouldn't change suggested config if set", async () => { - let config = { - ...DEFAULT_CONFIG, - compilerOptions: { - ...DEFAULT_CONFIG.compilerOptions, - strict: false, - moduleResolution: "NodeNext", - }, - }; - - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { - "tsconfig.json": json(config), - }, - }); - - let tsconfig = await getTsConfig(fixture.projectDir); - expect(tsconfig).toEqual(config); -}); - -test("shouldn't change suggested config for moduleResolution: bundler", async () => { - let config = { - ...DEFAULT_CONFIG, - compilerOptions: { - ...DEFAULT_CONFIG.compilerOptions, - strict: false, - moduleResolution: "bundler", - }, - }; - - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { - "tsconfig.json": json(config), - }, - }); - - let tsconfig = await getTsConfig(fixture.projectDir); - expect(tsconfig).toEqual(config); -}); - -test("allows for `extends` in tsconfig", async () => { - let config = { - extends: "./tsconfig.base.json", - }; - - let baseConfig = { - compilerOptions: { - allowJs: true, - baseUrl: ".", - }, - }; - - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { - "tsconfig.json": json(config), - "tsconfig.base.json": json(baseConfig), - }, - }); - - let tsconfig = await getTsConfig(fixture.projectDir); - - // our base config only sets a few options, so our local config should fill in the missing ones - let expected = JSON.parse(JSON.stringify({ ...DEFAULT_CONFIG })); - // these were defined by the base config - delete expected.compilerOptions.allowJs; - delete expected.compilerOptions.baseUrl; - - expect(tsconfig).toEqual({ - extends: "./tsconfig.base.json", - ...expected, - }); -}); - -test("works with jsconfig", async () => { - let config = { - compilerOptions: DEFAULT_CONFIG.compilerOptions, - }; - - let fixture = await createFixture({ - future: { v2_routeConvention: true }, - files: { - "jsconfig.json": json(config), - }, - }); - - let jsconfig = await getTsConfig(fixture.projectDir, "jsconfig.json"); - expect(jsconfig).toEqual({ - ...config, - include: ["**/*.js", "**/*.jsx"], - }); -}); From 88fcd7ea240124a2c7fb0bd26355c5a71ecb1d0f Mon Sep 17 00:00:00 2001 From: Logan McAnsh Date: Wed, 26 Apr 2023 20:42:57 -0400 Subject: [PATCH 3/3] Create tsconfig-no-modify.md --- .changeset/tsconfig-no-modify.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/tsconfig-no-modify.md diff --git a/.changeset/tsconfig-no-modify.md b/.changeset/tsconfig-no-modify.md new file mode 100644 index 00000000000..85dc55e2b76 --- /dev/null +++ b/.changeset/tsconfig-no-modify.md @@ -0,0 +1,6 @@ +--- +"remix": patch +"@remix-run/dev": patch +--- + +stop modifying a user's tsconfig when running using `getConfig` (`remix dev`, `remix routes`, `remix build`, etc)