From 68ed27abc07d23e9292123b9c2d13d421ffb5e67 Mon Sep 17 00:00:00 2001 From: Dominic Saadi Date: Mon, 22 Jan 2024 13:22:38 -0800 Subject: [PATCH] chore(esm): convert `@redwoodjs/project-config` to ESM (#9870) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm still working through a few things. The motivation for tackling `@redwoodjs/project-config` first was 1) most of our other package's depend on it 2) it's small 3) it would make merging the PR that converts the CLI's Jest tests to Vitest easier because Vitest can't mock require (see https://github.com/redwoodjs/redwood/pull/9863). I used [`arethetypeswrong/cli`](https://github.com/arethetypeswrong/arethetypeswrong.github.io) extensively. Right now I'm deeming the "Masquerading as ESM" error it emits acceptable. The code between the ESM and CJS files doesn't differ in functionality, only syntax; shipping two declaration copies of all the declaration files is shipping extra code. Mark Erikson did something similar at first at least here: > Unfortunately, no build tool that I knew of at that time did this by default, and the idea of shipping 99%-duplicate typedefs bothered me. So, I opted to not try to fix this "FalseCJS" issue for our packages (at least for the time being). (Source: https://blog.isquaredsoftware.com/2023/08/esm-modernization-lessons/#typescript-declarations.) Note that FalseCJS's fancier name is "Masquerading as CJS". We have "Masquerading as ESM", not CJS. I'm not sure if it's an issue that it's flipped yet. ``` $ attw ./redwoodjs-project-config.tgz @redwoodjs/project-config v6.0.7 Build tools: - typescript@5.3.3 - esbuild@0.19.9 👺 Import resolved to an ESM type declaration file, but a CommonJS JavaScript file. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseESM.md ┌───────────────────┬─────────────────────────────┐ │ │ "@redwoodjs/project-config" │ ├───────────────────┼─────────────────────────────┤ │ node10 │ 🟢 │ ├───────────────────┼─────────────────────────────┤ │ node16 (from CJS) │ 👺 Masquerading as ESM │ ├───────────────────┼─────────────────────────────┤ │ node16 (from ESM) │ 🟢 (ESM) │ ├───────────────────┼─────────────────────────────┤ │ bundler │ 🟢 │ └───────────────────┴─────────────────────────────┘ ``` Regarding the `.js` extensions (which are necessary for relative imports in ESM) in TS code, see https://github.com/redwoodjs/redwood/pull/8456. --- packages/project-config/build.js | 28 +++++++++++++++++++ packages/project-config/build.mjs | 22 --------------- packages/project-config/package.json | 7 +++-- packages/project-config/src/config.ts | 2 +- packages/project-config/src/configPath.ts | 2 +- packages/project-config/src/index.ts | 8 +++--- packages/project-config/src/paths.ts | 4 +-- packages/project-config/tsconfig.json | 2 ++ packages/vite/bins/rw-vite-dev.mjs | 4 +-- .../src/__tests__/viteNestedPages.test.mts | 3 +- 10 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 packages/project-config/build.js delete mode 100644 packages/project-config/build.mjs diff --git a/packages/project-config/build.js b/packages/project-config/build.js new file mode 100644 index 000000000000..4560f1d78590 --- /dev/null +++ b/packages/project-config/build.js @@ -0,0 +1,28 @@ +/* eslint-disable import/no-extraneous-dependencies */ + +import * as esbuild from 'esbuild' + +const options = { + entryPoints: ['./src/index.ts'], + outdir: 'dist', + + platform: 'node', + target: ['node20'], + bundle: true, + packages: 'external', + + logLevel: 'info', + metafile: true, +} + +await esbuild.build({ + ...options, + format: 'esm', + outExtension: { '.js': '.mjs' }, +}) + +await esbuild.build({ + ...options, + format: 'cjs', + outExtension: { '.js': '.cjs' }, +}) diff --git a/packages/project-config/build.mjs b/packages/project-config/build.mjs deleted file mode 100644 index 2cec19a1a453..000000000000 --- a/packages/project-config/build.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'node:fs' - -import * as esbuild from 'esbuild' - -const result = await esbuild.build({ - entryPoints: ['src/index.ts'], - outdir: 'dist', - - bundle: true, - - platform: 'node', - target: ['node20'], - packages: 'external', - - logLevel: 'info', - - // For visualizing the bundle. - // See https://esbuild.github.io/api/#metafile and https://esbuild.github.io/analyze/. - metafile: true, -}) - -fs.writeFileSync('meta.json', JSON.stringify(result.metafile)) diff --git a/packages/project-config/package.json b/packages/project-config/package.json index 6d3e4e692316..2c1e5f34767c 100644 --- a/packages/project-config/package.json +++ b/packages/project-config/package.json @@ -7,15 +7,18 @@ "directory": "packages/project-config" }, "license": "MIT", + "type": "module", "exports": { - ".": "./dist/index.js" + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "default": "./dist/index.cjs" }, "types": "./dist/index.d.ts", "files": [ "dist" ], "scripts": { - "build": "yarn node ./build.mjs && run build:types", + "build": "yarn node ./build.js && run build:types", "build:pack": "yarn pack -o redwoodjs-project-config.tgz", "build:types": "tsc --build --verbose", "build:watch": "nodemon --watch src --ext \"js,ts,tsx\" --ignore dist --exec \"yarn build\"", diff --git a/packages/project-config/src/config.ts b/packages/project-config/src/config.ts index e8dcdfda4146..4c226ac3ccde 100644 --- a/packages/project-config/src/config.ts +++ b/packages/project-config/src/config.ts @@ -4,7 +4,7 @@ import toml from '@iarna/toml' import merge from 'deepmerge' import { env as envInterpolation } from 'string-env-interpolation' -import { getConfigPath } from './configPath' +import { getConfigPath } from './configPath.js' export enum TargetEnum { NODE = 'node', diff --git a/packages/project-config/src/configPath.ts b/packages/project-config/src/configPath.ts index 697136284f2f..d24e85b039d9 100644 --- a/packages/project-config/src/configPath.ts +++ b/packages/project-config/src/configPath.ts @@ -1,4 +1,4 @@ -import { findUp } from './findUp' +import { findUp } from './findUp.js' const CONFIG_FILE_NAME = 'redwood.toml' diff --git a/packages/project-config/src/index.ts b/packages/project-config/src/index.ts index ae6da932ae6e..e420284a615d 100644 --- a/packages/project-config/src/index.ts +++ b/packages/project-config/src/index.ts @@ -1,4 +1,4 @@ -export * from './config' -export * from './configPath' -export * from './paths' -export * from './findUp' +export * from './config.js' +export * from './configPath.js' +export * from './paths.js' +export * from './findUp.js' diff --git a/packages/project-config/src/paths.ts b/packages/project-config/src/paths.ts index ed79fb75db34..62902ef16fa4 100644 --- a/packages/project-config/src/paths.ts +++ b/packages/project-config/src/paths.ts @@ -3,8 +3,8 @@ import path from 'path' import fg from 'fast-glob' -import { getConfig } from './config' -import { getConfigPath } from './configPath' +import { getConfig } from './config.js' +import { getConfigPath } from './configPath.js' export interface NodeTargetPaths { base: string diff --git a/packages/project-config/tsconfig.json b/packages/project-config/tsconfig.json index 74bdeb595478..78a31c197ddd 100644 --- a/packages/project-config/tsconfig.json +++ b/packages/project-config/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.compilerOption.json", "compilerOptions": { + "moduleResolution": "NodeNext", + "module": "NodeNext", "baseUrl": ".", "rootDir": "src", "outDir": "dist", diff --git a/packages/vite/bins/rw-vite-dev.mjs b/packages/vite/bins/rw-vite-dev.mjs index ba0e4e5a205a..b136728048b6 100755 --- a/packages/vite/bins/rw-vite-dev.mjs +++ b/packages/vite/bins/rw-vite-dev.mjs @@ -2,9 +2,9 @@ import { createServer } from 'vite' import yargsParser from 'yargs-parser' -import projectConfig from '@redwoodjs/project-config' +import { getPaths } from '@redwoodjs/project-config' -const rwPaths = projectConfig.getPaths() +const rwPaths = getPaths() const startDevServer = async () => { const configFile = rwPaths.web.viteConfig diff --git a/packages/vite/src/__tests__/viteNestedPages.test.mts b/packages/vite/src/__tests__/viteNestedPages.test.mts index ba38be25bbb5..27805d40a1b5 100644 --- a/packages/vite/src/__tests__/viteNestedPages.test.mts +++ b/packages/vite/src/__tests__/viteNestedPages.test.mts @@ -6,7 +6,7 @@ import { transformWithEsbuild } from 'vite' import { test, describe, beforeEach, afterAll, beforeAll, it, expect, vi } from 'vitest' import * as babel from '@babel/core' -import projectConfig from '@redwoodjs/project-config' +import { getPaths } from '@redwoodjs/project-config' import { Flags, @@ -41,7 +41,6 @@ async function transform(srcPath: string) { const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const FIXTURE_PATH = path.join(__dirname, 'fixtures/nestedPages') -const { getPaths } = projectConfig test('transform', async () => { vi.spyOn(fs, 'readFileSync').mockImplementationOnce(() => {