From ee59d82849dd72f593d1d39c0c91b073a3f63e92 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Fri, 18 Jun 2021 13:09:20 +0300 Subject: [PATCH 1/4] Add `"type": "module"` to `@apollo/client/core` Consider trying to load `@apollo/client/core` in node.js ```bash node -v # 16.3.0 ``` ```js // server/index.js import { ApolloClient } from '@apollo/client/core'; ``` > import { ApolloClient, InMemoryCache } from '@apollo/client/core/index.js'; > ^^^^^^^^^^^^ > SyntaxError: Named export 'ApolloClient' not found. The requested module '@apollo/client/core/index.js' is a CommonJS module, which may not support all module.exports as named exports. > CommonJS modules can always be imported via the default export, for example using: ```js import AC from '@apollo/client/core'; const { ApolloClient } = AC; ``` > (node:35704) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. > (Use `node --trace-warnings ...` to show where the warning was created) > /path/to/node_modules/@apollo/client/core/index.js:1 > export { ApolloClient, mergeOptions, } from "./ApolloClient.js"; > ^^^^^^ > > SyntaxError: Unexpected token 'export' adding `"type": "module"` to core will solve those errors nicely --- config/prepareDist.js | 1 + 1 file changed, 1 insertion(+) diff --git a/config/prepareDist.js b/config/prepareDist.js index 0a06adf0812..190dac04f70 100644 --- a/config/prepareDist.js +++ b/config/prepareDist.js @@ -73,6 +73,7 @@ entryPoints.forEach(function buildPackageJson({ module: 'index.js', types: 'index.d.ts', sideEffects, + ...dirs.includes('core') && { type: "module" }, }, null, 2) + "\n", ); }); From a597eff1d03b8f16d11572d8c67177632beaffcd Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Fri, 18 Jun 2021 13:11:56 +0300 Subject: [PATCH 2/4] use `"type": "module"` for all packages --- config/prepareDist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/prepareDist.js b/config/prepareDist.js index 190dac04f70..801cdfd21f5 100644 --- a/config/prepareDist.js +++ b/config/prepareDist.js @@ -69,11 +69,11 @@ entryPoints.forEach(function buildPackageJson({ path.join(distRoot, ...dirs, 'package.json'), JSON.stringify({ name: path.posix.join('@apollo', 'client', ...dirs), + type: "module", main: `${bundleName}.cjs.js`, module: 'index.js', types: 'index.d.ts', sideEffects, - ...dirs.includes('core') && { type: "module" }, }, null, 2) + "\n", ); }); From f5a7a58bf7c054f09b02a73cab80559544e7cf07 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 23 Jun 2021 10:45:07 -0400 Subject: [PATCH 3/4] Use just .cjs for CommonJS bundles, rather than .cjs.js. --- config/helpers.ts | 1 + config/prepareDist.js | 2 +- config/rollup.config.js | 8 ++++---- config/version.js | 16 ++++++++-------- package.json | 4 ++-- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/config/helpers.ts b/config/helpers.ts index 2c881a98b0e..2fcc9919b9d 100644 --- a/config/helpers.ts +++ b/config/helpers.ts @@ -23,6 +23,7 @@ export function eachFile(dir: string, callback: ( // Avoid re-transforming CommonJS bundle files. if (relPath.endsWith(".cjs.js")) return; + if (relPath.endsWith(".cjs")) return; // Avoid re-transforming CommonJS bundle files. if (relPath.endsWith(".min.js")) return; diff --git a/config/prepareDist.js b/config/prepareDist.js index 801cdfd21f5..5d35465337e 100644 --- a/config/prepareDist.js +++ b/config/prepareDist.js @@ -70,7 +70,7 @@ entryPoints.forEach(function buildPackageJson({ JSON.stringify({ name: path.posix.join('@apollo', 'client', ...dirs), type: "module", - main: `${bundleName}.cjs.js`, + main: `${bundleName}.cjs`, module: 'index.js', types: 'index.d.ts', sideEffects, diff --git a/config/rollup.config.js b/config/rollup.config.js index 90d381f7a5c..4e5892b6bae 100644 --- a/config/rollup.config.js +++ b/config/rollup.config.js @@ -77,7 +77,7 @@ function prepareCJSMinified(input) { return { input, output: { - file: input.replace('.js', '.min.js'), + file: input.replace('.cjs', '.min.cjs'), format: 'cjs', }, plugins: [ @@ -108,7 +108,7 @@ function prepareBundle({ return isExternal(id, parentId, true); }, output: { - file: `${dir}/${bundleName}.cjs.js`, + file: `${dir}/${bundleName}.cjs`, format: 'cjs', sourcemap: true, exports: 'named', @@ -125,10 +125,10 @@ export default [ // Convert the ESM entry point to a single CJS bundle. prepareCJS( './dist/core/index.js', - './dist/apollo-client.cjs.js', + './dist/apollo-client.cjs', ), // Minify that single CJS bundle. prepareCJSMinified( - './dist/apollo-client.cjs.js', + './dist/apollo-client.cjs', ), ]; diff --git a/config/version.js b/config/version.js index f48278fc6e8..0abf54fe5c9 100644 --- a/config/version.js +++ b/config/version.js @@ -31,7 +31,7 @@ switch (process.argv[2]) { const { ApolloClient, InMemoryCache, - } = require(path.join(distRoot, "core", "core.cjs.js")); + } = require(path.join(distRoot, "core", "core.cjs")); // Though this may seem like overkill, verifying that ApolloClient is // constructible in Node.js is actually pretty useful, too! @@ -43,15 +43,15 @@ switch (process.argv[2]) { // the client might have acquired during its construction. client.stop(); - // The CommonJS dist/core/core.cjs.js file is generated from ESM modules - // generated by tsc, including dist/version.js, so verifying core.cjs.js - // exports an ApolloClient class that defines client.version also serves - // to verify that dist/version.js must have been correctly updated, - // which is convenient because dist/version.js uses ECMAScript module - // syntax, and is thus not importable in all versions of Node.js. + // The CommonJS dist/core/core.cjs file is generated from ESM modules + // generated by tsc, including dist/version.js, so verifying core.cjs + // exports an ApolloClient class that defines client.version also serves to + // verify that dist/version.js must have been correctly updated, which is + // convenient because dist/version.js uses ECMAScript module syntax, and is + // thus not importable in all versions of Node.js. assert.strictEqual( client.version, version, - "Failed to update dist/version.js and dist/core/core.cjs.js", + "Failed to update dist/version.js and dist/core/core.cjs", ); break; diff --git a/package.json b/package.json index 5cbefd39b1a..9fa926c0f56 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ ], "author": "opensource@apollographql.com", "license": "MIT", - "main": "./dist/main.cjs.js", + "main": "./dist/main.cjs", "module": "./dist/index.js", "types": "./dist/index.d.ts", "sideEffects": false, @@ -54,7 +54,7 @@ "bundlesize": [ { "name": "apollo-client", - "path": "./dist/apollo-client.cjs.min.js", + "path": "./dist/apollo-client.min.cjs", "maxSize": "24.6 kB" } ], From 60e18e95b366c845501fc30f5e607ab5bf9d2035 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 23 Jun 2021 12:02:56 -0400 Subject: [PATCH 4/4] Make resolveModuleIds.ts resolve bare/non-relative package imports, too. For example, this rewrites the import from "ts-invariant/process" in @apollo/client/utilities/globals/graphql.js to instead import from "ts-invariant/process/index.js, so Node.js won't complain about the directory import (even though ts-invariant/process/package.json exists). --- config/resolveModuleIds.ts | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/config/resolveModuleIds.ts b/config/resolveModuleIds.ts index 061fd7a4826..37dec13b646 100644 --- a/config/resolveModuleIds.ts +++ b/config/resolveModuleIds.ts @@ -54,20 +54,44 @@ function isRelative(id: string) { } function normalizeSourceString(file: string, source?: Node | null) { - if (source && n.StringLiteral.check(source) && isRelative(source.value)) { + if (source && n.StringLiteral.check(source)) { try { - source.value = normalizeId(source.value, file); + source.value = isRelative(source.value) + ? normalizeId(source.value, file) + : normalizeNonRelativeId(source.value, file); } catch (error) { - console.error(`Failed to resolve ${source.value} in ${file}`); + console.error(`Failed to resolve ${source.value} in ${file} with error ${error}`); process.exit(1); } } } +function normalizeNonRelativeId(id: string, file: string) { + const normal = normalizeId(id, file); + const normalParts = normal.split("/"); + const sourceParts = id.split("/"); + const nodeModulesIndex = normalParts.lastIndexOf("node_modules"); + if ( + nodeModulesIndex >= 0 && + normalParts[nodeModulesIndex + 1] === sourceParts[0] + ) { + const bareModuleIdentifier = + normalParts.slice(nodeModulesIndex + 1).join("/"); + if (normal === normalizeId(bareModuleIdentifier, file)) { + return bareModuleIdentifier; + } + console.error(`Leaving ${id} import in ${file} unchanged because ${ + bareModuleIdentifier + } does not resolve to the same module`); + } + return id; +} + function normalizeId(id: string, file: string) { const basedir = path.dirname(file); const absPath = resolve.sync(id, { basedir, + extensions: [".mjs", ".js"], packageFilter(pkg) { return pkg.module ? { ...pkg,