Skip to content

Commit

Permalink
Generate ESM and CJS files; change to deep-import API
Browse files Browse the repository at this point in the history
The overall approach is to ask tsc to build two different projects for
package/server, one with CJS output and one with ESM, outputting into
two subdirectories of packages/server/dist. package.json teaches Node
how to find various entry points with both ESM and CJS.

To make the ESM version work, this equires making all "file imports"
(not `import type` or imports of packages) end with `.js`. Instead of
using `__dirname` we now update the version number in a normal TS file
before building.

We have to do some weird stuff with how we import the proto package
since it is not ESM-y enough due to the weird index.js in it. (Maybe we
should just fix our protobuf port to drop long support directly so we
can have a nicer index.js which is analyzed properly?)

We update the actual API so that `startStandaloneServer` must be
imported from `@apollo/server/standalone` (and thus express can be
tree-shaken if you don't use the standalone server) and so that the
various plugins are imported from `@apollo/server/plugin/usageReporting`
etc (and so you don't have to load protobuf stuff if you don't use it).
  • Loading branch information
glasser committed Jun 16, 2022
1 parent 89530f7 commit 2933fb4
Show file tree
Hide file tree
Showing 45 changed files with 420 additions and 173 deletions.
8 changes: 8 additions & 0 deletions .circleci/config.yml
Expand Up @@ -44,6 +44,13 @@ jobs:
- store_test_results:
path: junit.xml

Smoke test built package:
docker:
- image: cimg/base:stable
steps:
- setup-node
- run: npm run test:smoke

Prettier:
docker:
- image: cimg/base:stable
Expand Down Expand Up @@ -90,3 +97,4 @@ workflows:
- "Check for FIXM\x45"
- Prettier
- Spell check
- Smoke test built package
4 changes: 4 additions & 0 deletions cspell-dict.txt
Expand Up @@ -102,6 +102,7 @@ microrouter
middlewares
Middlewares
millis
mktemp
monodocs
mygraph
myvariant
Expand All @@ -119,6 +120,8 @@ pbts
pook
Pook
pooks
postcompile
precompile
preflighted
preflighting
prepended
Expand All @@ -135,6 +138,7 @@ retryable
revalidates
roadmap
ROADMAP
rollup
runtimes
safelist
safelisted
Expand Down
10 changes: 8 additions & 2 deletions jest.config.base.js
@@ -1,6 +1,6 @@
const { defaults } = require('jest-config');
import { defaults } from 'jest-config';

module.exports = {
export default {
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/../../jest.setup.js'],
preset: 'ts-jest',
Expand All @@ -9,10 +9,16 @@ module.exports = {
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
moduleFileExtensions: [...defaults.moduleFileExtensions, 'ts', 'tsx'],
clearMocks: true,
extensionsToTreatAsEsm: ['.ts'],
globals: {
'ts-jest': {
useESM: true,
tsconfig: '<rootDir>/src/__tests__/tsconfig.json',
diagnostics: false,
},
},
moduleNameMapper: {
// Ignore '.js' at the end of imports; part of ESM support.
'^(\\.{1,2}/.*)\\.js$': '$1',
},
};
31 changes: 5 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions package.json
Expand Up @@ -3,17 +3,22 @@
"private": true,
"license": "MIT",
"repository": "github:apollographql/apollo-server",
"type": "module",
"scripts": {
"clean": "git clean -dfqX -- ./node_modules **/{dist,node_modules}/ **/tsconfig*tsbuildinfo",
"compile": "tsc --build tsconfig.build.json",
"compile:clean": "tsc --build tsconfig.build.json --clean",
"precompile": "node precompile.mjs",
"postcompile": "node postcompile.mjs",
"compile": "tsc --build tsconfig.build.json packages/server/tsconfig.cjs.json; x=$?; mv packages/server/src/.packageVersion.ts.original packages/server/src/packageVersion.ts; exit $x",
"watch": "tsc --build tsconfig.build.json --watch",
"install-with-npm-8.5": "npm i -g npm@^8.5.0 && npm i",
"postinstall": "npm run compile",
"pretest": "tsc --build tsconfig.json",
"test": "jest --verbose",
"test:clean": "jest --clearCache",
"test:watch": "jest --verbose --watchAll",
"test:smoke": "npm run test:smoke:prepare && npm run test:smoke:run",
"test:smoke:prepare": "npm run compile && smoke-test/prepare.sh",
"test:smoke:run": "smoke-test/smoke-test.sh",
"testonly": "npm test",
"test:ci": "npm run coverage -- --ci --maxWorkers=2 --reporters=default --reporters=jest-junit",
"coverage": "npm test -- --coverage",
Expand All @@ -40,7 +45,6 @@
"@graphql-tools/utils": "8.6.13",
"@josephg/resolvable": "1.0.1",
"@rollup/plugin-commonjs": "22.0.0",
"@rollup/plugin-json": "4.1.0",
"@types/async-retry": "1.4.4",
"@types/body-parser": "1.19.2",
"@types/cors": "2.8.12",
Expand Down Expand Up @@ -83,6 +87,7 @@
"qs-middleware": "1.0.3",
"request-promise": "4.2.6",
"requisition": "1.7.0",
"rimraf": "^3.0.2",
"rollup": "2.75.6",
"supertest": "6.2.3",
"test-listen": "1.1.0",
Expand Down
1 change: 1 addition & 0 deletions packages/server/.npmignore
Expand Up @@ -3,5 +3,6 @@
src/**/__tests__/**
!dist/**/*
dist/**/__tests__/**
dist/**/*.tsbuildinfo
!package.json
!README.md
4 changes: 2 additions & 2 deletions packages/server/jest.config.js
@@ -1,3 +1,3 @@
const config = require('../../jest.config.base');
import baseConfig from '../../jest.config.base.js';

module.exports = Object.assign(Object.create(null), config);
export default baseConfig;
52 changes: 31 additions & 21 deletions packages/server/package.json
Expand Up @@ -2,47 +2,57 @@
"name": "@apollo/server",
"version": "3.6.7",
"description": "Core engine for Apollo GraphQL server",
"type": "commonjs",
"type": "module",
"exports": {
".": {
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js",
"types": "./dist/cjs/index.d.ts"
},
"./standalone": {
"require": "./dist/standalone/index.js",
"types": "./dist/standalone/index.d.ts"
"import": "./dist/esm/standalone/index.js",
"require": "./dist/cjs/standalone/index.js",
"types": "./dist/cjs/standalone/index.d.ts"
},
"./plugin/cacheControl": {
"require": "./dist/plugin/cacheControl/index.js",
"types": "./dist/plugin/cacheControl/index.d.ts"
"import": "./dist/esm/plugin/cacheControl/index.js",
"require": "./dist/cjs/plugin/cacheControl/index.js",
"types": "./dist/cjs/plugin/cacheControl/index.d.ts"
},
"./plugin/disabled": {
"require": "./dist/plugin/disabled.js",
"types": "./dist/plugin/disabled.d.ts"
"import": "./dist/esm/plugin/disabled.js",
"require": "./dist/cjs/plugin/disabled.js",
"types": "./dist/cjs/plugin/disabled.d.ts"
},
"./plugin/drainHttpServer": {
"require": "./dist/plugin/drainHttpServer/index.js",
"types": "./dist/plugin/drainHttpServer/index.d.ts"
"import": "./dist/esm/plugin/drainHttpServer/index.js",
"require": "./dist/cjs/plugin/drainHttpServer/index.js",
"types": "./dist/cjs/plugin/drainHttpServer/index.d.ts"
},
"./plugin/inlineTrace": {
"require": "./dist/plugin/inlineTrace/index.js",
"types": "./dist/plugin/inlineTrace/index.d.ts"
"import": "./dist/esm/plugin/inlineTrace/index.js",
"require": "./dist/cjs/plugin/inlineTrace/index.js",
"types": "./dist/cjs/plugin/inlineTrace/index.d.ts"
},
"./plugin/landingPage/default": {
"require": "./dist/plugin/landingPage/default/index.js",
"types": "./dist/plugin/landingPage/default/index.d.ts"
"import": "./dist/esm/plugin/landingPage/default/index.js",
"require": "./dist/cjs/plugin/landingPage/default/index.js",
"types": "./dist/cjs/plugin/landingPage/default/index.d.ts"
},
"./plugin/landingPage/graphqlPlayground": {
"require": "./dist/plugin/landingPage/graphqlPlayground/index.js",
"types": "./dist/plugin/landingPage/graphqlPlayground/index.d.ts"
"import": "./dist/esm/plugin/landingPage/graphqlPlayground/index.js",
"require": "./dist/cjs/plugin/landingPage/graphqlPlayground/index.js",
"types": "./dist/cjs/plugin/landingPage/graphqlPlayground/index.d.ts"
},
"./plugin/schemaReporting": {
"require": "./dist/plugin/schemaReporting/index.js",
"types": "./dist/plugin/schemaReporting/index.d.ts"
"import": "./dist/esm/plugin/schemaReporting/index.js",
"require": "./dist/cjs/plugin/schemaReporting/index.js",
"types": "./dist/cjs/plugin/schemaReporting/index.d.ts"
},
"./plugin/usageReporting": {
"require": "./dist/plugin/usageReporting/index.js",
"types": "./dist/plugin/usageReporting/index.d.ts"
"import": "./dist/esm/plugin/usageReporting/index.js",
"require": "./dist/cjs/plugin/usageReporting/index.js",
"types": "./dist/cjs/plugin/usageReporting/index.d.ts"
}
},
"repository": {
Expand Down
30 changes: 15 additions & 15 deletions packages/server/src/ApolloServer.ts
Expand Up @@ -23,9 +23,9 @@ import {
import loglevel from 'loglevel';
import Negotiator from 'negotiator';
import * as uuid from 'uuid';
import { newCachePolicy } from './cachePolicy';
import { determineApolloConfig } from './determineApolloConfig';
import { BadRequestError, ensureError, formatApolloErrors } from './errors';
import { newCachePolicy } from './cachePolicy.js';
import { determineApolloConfig } from './determineApolloConfig.js';
import { BadRequestError, ensureError, formatApolloErrors } from './errors.js';
import type {
ApolloServerPlugin,
BaseContext,
Expand All @@ -44,22 +44,22 @@ import type {
HTTPGraphQLHead,
ContextThunk,
} from './externalTypes';
import { runPotentiallyBatchedHttpQuery } from './httpBatching';
import { InternalPluginId, pluginIsInternal } from './internalPlugin';
import { runPotentiallyBatchedHttpQuery } from './httpBatching.js';
import { InternalPluginId, pluginIsInternal } from './internalPlugin.js';
import {
preventCsrf,
recommendedCsrfPreventionRequestHeaders,
} from './preventCsrf';
import { APQ_CACHE_PREFIX, processGraphQLRequest } from './requestPipeline';
} from './preventCsrf.js';
import { APQ_CACHE_PREFIX, processGraphQLRequest } from './requestPipeline.js';
import {
badMethodErrorMessage,
cloneObject,
HeaderMap,
newHTTPGraphQLHead,
prettyJSONStringify,
} from './runHttpQuery';
import { SchemaManager } from './utils/schemaManager';
import { isDefined } from './utils/isDefined';
} from './runHttpQuery.js';
import { SchemaManager } from './utils/schemaManager.js';
import { isDefined } from './utils/isDefined.js';
import type { WithRequired } from '@apollo/utils.withrequired';
import type { ApolloServerOptionsWithStaticSchema } from './externalTypes/constructor';

Expand Down Expand Up @@ -857,7 +857,7 @@ export class ApolloServer<TContext extends BaseContext = BaseContext> {
{
if (!alreadyHavePluginWithInternalId('CacheControl')) {
const { ApolloServerPluginCacheControl } = await import(
'./plugin/cacheControl'
'./plugin/cacheControl/index.js'
);
plugins.push(ApolloServerPluginCacheControl());
}
Expand All @@ -874,7 +874,7 @@ export class ApolloServer<TContext extends BaseContext = BaseContext> {
// the fact that the person who wrote this line also was the original
// author of the comment above in #1105, they don't quite understand why this was important.)
const { ApolloServerPluginUsageReporting } = await import(
'./plugin/usageReporting'
'./plugin/usageReporting/index.js'
);
plugins.unshift(ApolloServerPluginUsageReporting());
} else {
Expand All @@ -896,7 +896,7 @@ export class ApolloServer<TContext extends BaseContext = BaseContext> {
if (!alreadyHavePlugin && enabledViaEnvVar) {
if (apolloConfig.key) {
const { ApolloServerPluginSchemaReporting } = await import(
'./plugin/schemaReporting'
'./plugin/schemaReporting/index.js'
);
plugins.push(ApolloServerPluginSchemaReporting());
} else {
Expand All @@ -921,7 +921,7 @@ export class ApolloServer<TContext extends BaseContext = BaseContext> {
// pre-ApolloServerPluginInlineTrace where we would also avoid doing
// this if an API key was configured and log a warning.)
const { ApolloServerPluginInlineTrace } = await import(
'./plugin/inlineTrace'
'./plugin/inlineTrace/index.js'
);
plugins.push(
ApolloServerPluginInlineTrace({ __onlyIfSchemaIsFederated: true }),
Expand Down Expand Up @@ -949,7 +949,7 @@ export class ApolloServer<TContext extends BaseContext = BaseContext> {
const {
ApolloServerPluginLandingPageLocalDefault,
ApolloServerPluginLandingPageProductionDefault,
} = await import('./plugin/landingPage/default');
} = await import('./plugin/landingPage/default/index.js');
const plugin: ApolloServerPlugin<TContext> = isDev
? ApolloServerPluginLandingPageLocalDefault()
: ApolloServerPluginLandingPageProductionDefault();
Expand Down
@@ -1,7 +1,5 @@
const http = require('http');
const {
Stopper,
} = require('../../../../../dist/plugin/drainHttpServer/stoppable.js');
import http from 'http';
import { Stopper } from '../../../../../dist/esm/plugin/drainHttpServer/stoppable.js';

const grace = Number(process.argv[2] || Infinity);
let stopper;
Expand Down
7 changes: 3 additions & 4 deletions packages/server/src/__tests__/rollupCommonJs.test.ts
@@ -1,5 +1,4 @@
const rollup = require('rollup');
import json from '@rollup/plugin-json';
import commonjs from '@rollup/plugin-commonjs';
import path from 'path';

Expand All @@ -9,16 +8,16 @@ describe('@rollup/plugin-commonjs', () => {
exports: 'named',
name: 'apollo',
format: 'umd',
sourcemapExcludeSources: false,
};
const bundle = await rollup.rollup({
input: path.resolve(__dirname, '..', '..', 'dist', 'index.js'),
plugins: [json(), commonjs()],
input: path.resolve(__dirname, '..', '..', 'dist', 'cjs', 'index.js'),
plugins: [commonjs()],
onwarn: () => {
/* suppress warnings */
},
});
const { output } = await bundle.generate(outputOptions);
await bundle.close();
const indexBundle = output[0].code;
var varDefinedAfterBundle;
eval(`${indexBundle}; varDefinedAfterBundle = 'foo';`);
Expand Down

0 comments on commit 2933fb4

Please sign in to comment.