From 8cbf9b357edaff86be381e46619a7942b0082618 Mon Sep 17 00:00:00 2001 From: Joshua Date: Wed, 12 Jul 2023 09:20:48 -0700 Subject: [PATCH] refactor: Deprecate Rollup strategy. --- package-lock.json | 49 +++--- package.json | 4 - src/lib/configuration/loader.ts | 25 +-- src/lib/configuration/strategies/esbuild.ts | 3 +- src/lib/configuration/strategies/rollup.ts | 154 ------------------ tests/fixtures/cjs/ts-extension/app.config.ts | 2 +- tests/fixtures/esm/ts-extension/app.config.ts | 4 +- 7 files changed, 35 insertions(+), 206 deletions(-) delete mode 100644 src/lib/configuration/strategies/rollup.ts diff --git a/package-lock.json b/package-lock.json index d254884..8e96a21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,6 @@ "@darkobits/log": "^2.0.0-beta.15", "@darkobits/valida": "^0.1.6", "@esbuild-plugins/tsconfig-paths": "^0.1.2", - "@rollup/plugin-typescript": "^11.1.2", "@types/yargs": "^17.0.24", "camelcase-keys": "^8.0.2", "cosmiconfig": "^8.2.0", @@ -20,10 +19,7 @@ "esbuild": "^0.18.11", "esbuild-node-externals": "^1.8.0", "fs-extra": "^11.1.1", - "node-version": "^3.0.0", "read-pkg-up": "^10.0.0", - "rollup": "^3.26.2", - "rollup-plugin-node-externals": "^6.1.1", "tsconfck": "^2.1.1", "yargs": "^17.7.2" }, @@ -1772,6 +1768,7 @@ "version": "11.1.2", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.2.tgz", "integrity": "sha512-0ghSOCMcA7fl1JM+0gYRf+Q/HWyg+zg7/gDSc+fRLmlJWcW5K1I+CLRzaRhXf4Y3DRyPnnDo4M2ktw+a6JcDEg==", + "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", "resolve": "^1.22.1" @@ -1797,6 +1794,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", @@ -2478,7 +2476,8 @@ "node_modules/@types/estree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true }, "node_modules/@types/fs-extra": { "version": "11.0.1", @@ -4645,9 +4644,9 @@ } }, "node_modules/conventional-changelog-core/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "peer": true, "bin": { @@ -6332,9 +6331,9 @@ } }, "node_modules/eslint-plugin-unicorn/node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "peer": true, "bin": { @@ -6703,7 +6702,8 @@ "node_modules/estree-walker": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true }, "node_modules/esutils": { "version": "2.0.3", @@ -7126,6 +7126,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -9689,9 +9690,9 @@ } }, "node_modules/meow/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "peer": true, "bin": { @@ -10280,6 +10281,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/node-version/-/node-version-3.0.0.tgz", "integrity": "sha512-lOtS3Vaqo4GntMFYyH6BXbpiqgD5F+5ycBwDYaCjzBA9pKK9G1j6cKVtu3HU0HATDTikcWOTn8MxQmj/jo4iTQ==", + "dev": true, + "peer": true, "engines": { "node": ">=14.0.0" } @@ -14849,7 +14852,8 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true }, "node_modules/path-scurry": { "version": "1.10.1", @@ -14913,6 +14917,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "engines": { "node": ">=8.6" }, @@ -15800,6 +15805,7 @@ "version": "1.22.2", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dev": true, "dependencies": { "is-core-module": "^2.11.0", "path-parse": "^1.0.7", @@ -15893,6 +15899,8 @@ "version": "3.26.2", "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.26.2.tgz", "integrity": "sha512-6umBIGVz93er97pMgQO08LuH3m6PUb3jlDUUGFsNJB6VgTCUaDFpupf5JfU30529m/UKOgmiX+uY6Sx8cOYpLA==", + "dev": true, + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -15908,6 +15916,8 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/rollup-plugin-node-externals/-/rollup-plugin-node-externals-6.1.1.tgz", "integrity": "sha512-127OFMkpH5rBVlRHRBDUMk1m1sGuzbGy7so5aj/IkpUb2r3+wOWjR/erUzd2ChEQWPsxsyQG6xpYYvPBAdcBRA==", + "dev": true, + "peer": true, "engines": { "node": ">=16.0.0" }, @@ -16321,9 +16331,9 @@ } }, "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -17279,6 +17289,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, "engines": { "node": ">= 0.4" }, diff --git a/package.json b/package.json index 772538c..03fcb3c 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "@darkobits/log": "^2.0.0-beta.15", "@darkobits/valida": "^0.1.6", "@esbuild-plugins/tsconfig-paths": "^0.1.2", - "@rollup/plugin-typescript": "^11.1.2", "@types/yargs": "^17.0.24", "camelcase-keys": "^8.0.2", "cosmiconfig": "^8.2.0", @@ -35,10 +34,7 @@ "esbuild": "^0.18.11", "esbuild-node-externals": "^1.8.0", "fs-extra": "^11.1.1", - "node-version": "^3.0.0", "read-pkg-up": "^10.0.0", - "rollup": "^3.26.2", - "rollup-plugin-node-externals": "^6.1.1", "tsconfck": "^2.1.1", "yargs": "^17.7.2" }, diff --git a/src/lib/configuration/loader.ts b/src/lib/configuration/loader.ts index 5a2a648..a7f939a 100644 --- a/src/lib/configuration/loader.ts +++ b/src/lib/configuration/loader.ts @@ -5,7 +5,6 @@ import merge from 'deepmerge'; import validators from 'etc/validators'; import { esbuildStrategy } from 'lib/configuration/strategies/esbuild'; -import { rollupStrategy } from 'lib/configuration/strategies/rollup'; import log from 'lib/log'; import { getPackageInfo } from 'lib/package'; @@ -77,13 +76,7 @@ async function ecmaScriptLoader(filePath: string /* , contents: string */) { /** * Strategy 2: esbuild * - * This strategy will work for files that: - * - import nothing - * - only import other code that does not require a transpilation step - * - do not use any custom path mappings - * - * It is faster than Rollup and should cover the vast majority of cases where - * a simple dynamic import will not work. + * Uses esbuild to transpile the indicated file. */ try { const result = await esbuildStrategy(filePath, pkgInfo); @@ -94,22 +87,6 @@ async function ecmaScriptLoader(filePath: string /* , contents: string */) { } - /** - * Strategy 3: Rollup - * - * This is the slowest strategy, but the most robust. It will inline and - * transpile any code that the configuration file imports, allowing the - * output file to be imported as a standalone bundle. - */ - try { - const result = await rollupStrategy(filePath, pkgInfo); - log.verbose(prefix, 'Used strategy:', log.chalk.bold('rollup')); - return getDefaultExport(result); - } catch (err: any) { - errors.push(new Error(`${prefix} Failed to load file with ${log.chalk.bold('rollup')}: ${err}`)); - } - - if (errors.length > 0) throw new AggregateError(errors, 'All parsing strategies failed.'); } diff --git a/src/lib/configuration/strategies/esbuild.ts b/src/lib/configuration/strategies/esbuild.ts index eb4f6ec..f2ed0b7 100644 --- a/src/lib/configuration/strategies/esbuild.ts +++ b/src/lib/configuration/strategies/esbuild.ts @@ -4,7 +4,6 @@ import { TsconfigPathsPlugin } from '@esbuild-plugins/tsconfig-paths'; import * as esbuild from 'esbuild'; import { nodeExternalsPlugin } from 'esbuild-node-externals'; import fs from 'fs-extra'; -import currentNodeVersion from 'node-version'; import * as tsConfck from 'tsconfck'; import log from 'lib/log'; @@ -70,7 +69,7 @@ export async function esbuildStrategy(filePath: string, pkgInfo: Packag try { const buildOptions: esbuild.BuildOptions = { entryPoints: [filePath], - target: `node${currentNodeVersion.major}`, + target: 'node16', outfile: tempFilePath, format, platform: 'node', diff --git a/src/lib/configuration/strategies/rollup.ts b/src/lib/configuration/strategies/rollup.ts deleted file mode 100644 index 33d0464..0000000 --- a/src/lib/configuration/strategies/rollup.ts +++ /dev/null @@ -1,154 +0,0 @@ -import path from 'path'; - -import typescriptPlugin from '@rollup/plugin-typescript'; -import fs from 'fs-extra'; -import { - rollup, - type InputOptions, - type OutputOptions -} from 'rollup'; -import { nodeExternals } from 'rollup-plugin-node-externals'; -import * as tsConfck from 'tsconfck'; - -import log from 'lib/log'; - -import type { PackageInfo } from 'lib/package'; - - -/** - * Map of input extensions to output extensions that Node can natively import. - */ -const EXT_MAP: Record = { - '.js': '.js', - '.ts': '.js', - '.tsx': '.js', - '.jsx':' .js', - // User explicitly wants CommonJS. - '.cts': '.cjs', - '.cjs': '.cjs', - // User explicitly wants ESM. - '.mts': '.mjs', - '.mjs': '.mjs' -}; - - -/** - * tsConfck will throw if provided a `root` and fails to find a tsconfig file. - * - * TODO: Update other strategies. - */ -async function findTsConfig(filePath: string, root: string) { - try { - return await tsConfck.find(filePath, { root }); - } catch { - return false; - } -} - - -/** - * Uses Rollup to transpile the file at `filePath` by creating a temporary - * file in the same directory, then attempts to dynamically import it. An - * output format and extension are chosen based on the host project's - * "type" setting that are the least likely to produce errors. Once imported, - * the temporary file is removed. - */ -export async function rollupStrategy(filePath: string, pkgInfo: PackageInfo): Promise { - const prefix = log.prefix('strategy:rollup'); - - const parsedFilePath = path.parse(filePath); - const isExplicitCommonJs = ['.cjs', '.cts'].includes(parsedFilePath.ext); - const isExplicitESM = ['.mjs', '.mts'].includes(parsedFilePath.ext); - const outExt = EXT_MAP[parsedFilePath.ext]; - - if (!outExt) throw new Error( - `${prefix} Unable to determine output file extension from input extension: ${parsedFilePath.ext}` - ); - - // Determine the output format to use by first honoring any explicit - // transpilation hints based on file extension, then fall back to relying on - // the "type" field in package.json. The aim here is to use an output format - // that is the least likely to produce errors when being dynamically imported. - const format = isExplicitESM - ? 'es' - : isExplicitCommonJs - ? 'cjs' - : pkgInfo.json?.type === 'module' - ? 'es' - : 'cjs'; - - log.verbose(prefix, `Using format: ${log.chalk.bold(format)}`); - - const tempFileName = `.${parsedFilePath.name}.${Date.now()}${outExt}`; - const tempFilePath = path.join(path.dirname(filePath), tempFileName); - - log.verbose(prefix, `Temporary file path: ${log.chalk.green(tempFilePath)}`); - - try { - if (!pkgInfo.root) throw new Error('Unable to determine package root.'); - - const inputOptions: InputOptions = { - input: filePath, - plugins: [ - nodeExternals({ - builtinsPrefix: 'ignore', - packagePath: path.resolve(pkgInfo.root, 'package.json'), - deps: true, - devDeps: true, - peerDeps: true, - optDeps: true - }) - ] - }; - - // If the user has a TypeScript configuration file, enable TypeScript - // features. - const tsConfigFilePath = await findTsConfig(filePath, pkgInfo.root); - - if (tsConfigFilePath && Array.isArray(inputOptions.plugins)) { - log.verbose(prefix, 'Using TypeScript configuration:', log.chalk.green(tsConfigFilePath)); - // Add TypeScript config to inputOptions here. - inputOptions.plugins?.push(typescriptPlugin({ - sourceMap: false, - outputToFilesystem: false - })); - } - - const bundle = await rollup(inputOptions); - - const outputOptions: OutputOptions = { - format, - sourcemap: false - }; - - const { output } = await bundle.generate(outputOptions); - - for (const chunk of output) { - if (chunk.type === 'chunk') { - // log.info(prefix, chunk.code); - // console.log(''); - await fs.writeFile(tempFilePath, chunk.code); - } - } - } catch (err: any) { - // Handle any transpilation-related errors. - throw new Error( - `${log.chalk.red(`[${prefix}] Failed to transpile ${filePath}:`)} ${err.message}`, - { cause: err } - ); - } - - try { - // Import the temporary file and return the result. - return await import(tempFilePath); - } catch (err: any) { - // Handle any import-related errors. - throw new Error( - `${log.chalk.red(`[${prefix}] Failed to import() ${filePath}:`)} ${err.message}`, - { cause: err } - ); - } finally { - // Remove the temporary file. - if (await fs.exists(tempFilePath)) await fs.remove(tempFilePath); - } -} diff --git a/tests/fixtures/cjs/ts-extension/app.config.ts b/tests/fixtures/cjs/ts-extension/app.config.ts index 9d386ec..8c86b57 100644 --- a/tests/fixtures/cjs/ts-extension/app.config.ts +++ b/tests/fixtures/cjs/ts-extension/app.config.ts @@ -1,7 +1,7 @@ import { testFn } from './src/lib/utils'; // This tests that we can resolve paths to other files that themselves require -// a compilation step. Specifically, the Rollup strategy should be used, and +// a compilation step. Specifically, the esbuild strategy should be used, and // the imported values should be inlined into the final config file. if (!testFn()) { throw new Error('testFn failed'); diff --git a/tests/fixtures/esm/ts-extension/app.config.ts b/tests/fixtures/esm/ts-extension/app.config.ts index 43d11e3..ac41955 100644 --- a/tests/fixtures/esm/ts-extension/app.config.ts +++ b/tests/fixtures/esm/ts-extension/app.config.ts @@ -1,4 +1,4 @@ -// This is here to test that Rollup handles externals properly. +// This is here to test that esbuild handles externals properly. import path from 'path'; // This file should get transpiled to ESM because we have type: module in @@ -7,7 +7,7 @@ import path from 'path'; import { testFn } from 'lib/utils'; // This tests that we can resolve paths to other files that themselves require -// a compilation step. Specifically, the Rollup strategy should be used, and +// a compilation step. Specifically, the esbuild strategy should be used, and // the imported values should be inlined into the final config file. if (!testFn()) throw new Error('testFn failed');