Skip to content

Commit

Permalink
deploy full ESM with "type": "module" in "latest-esm" npm tag (#3361)
Browse files Browse the repository at this point in the history
  • Loading branch information
PabloSzx authored Sep 21, 2022
1 parent 3e5239f commit 87d003d
Show file tree
Hide file tree
Showing 16 changed files with 154 additions and 38 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/node_modules
/reports
/npmDist
/npmEsmDist
/denoDist
/websiteDist

Expand Down
4 changes: 4 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,10 @@ rules:
yield-star-spacing: off

overrides:
- files:
- 'integrationTests/node-esm/**/*.js'
parserOptions:
sourceType: module
- files: '**/*.ts'
parser: '@typescript-eslint/parser'
parserOptions:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
/node_modules
/reports
/npmDist
/npmEsmDist
/denoDist
/websiteDist
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
/node_modules
/reports
/npmDist
/npmEsmDist
/denoDist
/websiteDist
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
import assert from 'assert';
import { readFileSync } from 'fs';

import { graphqlSync } from 'graphql';
import { buildSchema } from 'graphql/utilities';
import { version } from 'graphql/version';
import { graphqlSync } from 'graphql-esm';
import { buildSchema } from 'graphql-esm/utilities';
import { version } from 'graphql-esm/version';

assert.deepStrictEqual(
version,
JSON.parse(readFileSync('./node_modules/graphql/package.json')).version,
version + '+esm',
JSON.parse(readFileSync('./node_modules/graphql-esm/package.json')).version,
);

const schema = buildSchema('type Query { hello: String }');
Expand Down
3 changes: 2 additions & 1 deletion integrationTests/node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"test": "node test.js"
},
"dependencies": {
"graphql": "file:../graphql.tgz"
"graphql": "file:../graphql.tgz",
"graphql-esm": "file:../graphql-esm.tgz"
}
}
7 changes: 6 additions & 1 deletion integrationTests/node/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ for (const version of nodeVersions) {
console.log(`Testing on node@${version} ...`);

childProcess.execSync(
`docker run --rm --volume "$PWD":/usr/src/app -w /usr/src/app node:${version}-slim node ./index.js`,
`docker run --rm --volume "$PWD":/usr/src/app -w /usr/src/app node:${version}-slim node ./index.cjs`,
{ stdio: 'inherit' },
);

childProcess.execSync(
`docker run --rm --volume "$PWD":/usr/src/app -w /usr/src/app node:${version}-slim node ./index.mjs`,
{ stdio: 'inherit' },
);
}
38 changes: 38 additions & 0 deletions integrationTests/ts/esm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { ExecutionResult } from 'graphql-esm/execution';

import { graphqlSync } from 'graphql-esm';
import {
GraphQLString,
GraphQLSchema,
GraphQLObjectType,
} from 'graphql-esm/type';

const queryType: GraphQLObjectType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
sayHi: {
type: GraphQLString,
args: {
who: {
type: GraphQLString,
defaultValue: 'World',
},
},
resolve(_root, args: { who: string }) {
return 'Hello ' + args.who;
},
},
}),
});

const schema: GraphQLSchema = new GraphQLSchema({ query: queryType });

const result: ExecutionResult = graphqlSync({
schema,
source: `
query helloWho($who: String){
test(who: $who)
}
`,
variableValues: { who: 'Dolly' },
});
1 change: 1 addition & 0 deletions integrationTests/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"dependencies": {
"graphql": "file:../graphql.tgz",
"graphql-esm": "file:../graphql-esm.tgz",
"typescript-4.4": "npm:[email protected]",
"typescript-4.5": "npm:[email protected]",
"typescript-4.6": "npm:[email protected]",
Expand Down
13 changes: 13 additions & 0 deletions integrationTests/webpack/entry-esm.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// eslint-disable-next-line node/no-missing-import, import/no-unresolved
import { graphqlSync } from 'graphql-esm';

// eslint-disable-next-line node/no-missing-import, import/no-unresolved
import { buildSchema } from 'graphql-esm/utilities/buildASTSchema';

const schema = buildSchema('type Query { hello: String }');

export const result = graphqlSync({
schema,
source: '{ hello }',
rootValue: { hello: 'world' },
});
1 change: 1 addition & 0 deletions integrationTests/webpack/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
},
"dependencies": {
"graphql": "file:../graphql.tgz",
"graphql-esm": "file:../graphql-esm.tgz",
"webpack": "5.x.x",
"webpack-cli": "4.x.x"
}
Expand Down
13 changes: 11 additions & 2 deletions integrationTests/webpack/test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import assert from 'assert';

import mainCJS from './dist/main.cjs';
import cjs from './dist/main-cjs.cjs';
import mjs from './dist/main-mjs.cjs';

assert.deepStrictEqual(mainCJS.result, {
assert.deepStrictEqual(cjs.result, {
data: {
__proto__: null,
hello: 'world',
},
});

assert.deepStrictEqual(mjs.result, {
data: {
__proto__: null,
hello: 'world',
},
});

console.log('Test script: Got correct result from Webpack bundle!');
7 changes: 5 additions & 2 deletions integrationTests/webpack/webpack.config.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
{
"mode": "production",
"entry": "./entry.js",
"entry": {
"cjs": "./entry.js",
"mjs": "./entry-esm.mjs"
},
"output": {
"filename": "main.cjs",
"filename": "main-[name].cjs",
"library": {
"type": "commonjs2"
}
Expand Down
79 changes: 53 additions & 26 deletions resources/build-npm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'node:path';

import ts from 'typescript';

import { changeExtensionInImportPaths } from './change-extension-in-import-paths.js';
import { inlineInvariant } from './inline-invariant.js';
import {
readPackageJSON,
Expand All @@ -12,17 +13,20 @@ import {
writeGeneratedFile,
} from './utils.js';

buildPackage();
console.log('\n./npmDist');
buildPackage('./npmDist', false);
showDirStats('./npmDist');

function buildPackage() {
fs.rmSync('./npmDist', { recursive: true, force: true });
fs.mkdirSync('./npmDist');
console.log('\n./npmEsmDist');
buildPackage('./npmEsmDist', true);
showDirStats('./npmEsmDist');

fs.copyFileSync('./LICENSE', './npmDist/LICENSE');
fs.copyFileSync('./README.md', './npmDist/README.md');
function buildPackage(outDir: string, isESMOnly: boolean): void {
fs.rmSync(outDir, { recursive: true, force: true });
fs.mkdirSync(outDir);

const { emittedTSFiles } = emitTSFiles('./npmDist');
fs.copyFileSync('./LICENSE', `./${outDir}/LICENSE`);
fs.copyFileSync('./README.md', `./${outDir}/README.md`);

const packageJSON = readPackageJSON();

Expand All @@ -39,7 +43,7 @@ function buildPackage() {
// TODO: revisit once TS implements https://github.com/microsoft/TypeScript/issues/32166
const notSupportedTSVersionFile = 'NotSupportedTSVersion.d.ts';
fs.writeFileSync(
path.join('./npmDist', notSupportedTSVersionFile),
path.join(outDir, notSupportedTSVersionFile),
// Provoke syntax error to show this message
`"Package 'graphql' support only TS versions that are ${supportedTSVersions[0]}".`,
);
Expand All @@ -49,19 +53,6 @@ function buildPackage() {
'*': { '*': [notSupportedTSVersionFile] },
};

packageJSON.exports = {};

for (const filepath of emittedTSFiles) {
if (path.basename(filepath) === 'index.js') {
const relativePath = './' + path.relative('./npmDist', filepath);
packageJSON.exports[path.dirname(relativePath)] = relativePath;
}
}

// Temporary workaround to allow "internal" imports, no grantees provided
packageJSON.exports['./*.js'] = './*.js';
packageJSON.exports['./*'] = './*.js';

// TODO: move to integration tests
const publishTag = packageJSON.publishConfig?.tag;
assert(publishTag != null, 'Should have packageJSON.publishConfig defined!');
Expand Down Expand Up @@ -90,16 +81,51 @@ function buildPackage() {
);
}

if (isESMOnly) {
packageJSON.exports = {};

const { emittedTSFiles } = emitTSFiles({
outDir,
module: 'es2020',
extension: '.js',
});

for (const filepath of emittedTSFiles) {
if (path.basename(filepath) === 'index.js') {
const relativePath = './' + path.relative('./npmEsmDist', filepath);
packageJSON.exports[path.dirname(relativePath)] = relativePath;
}
}

// Temporary workaround to allow "internal" imports, no grantees provided
packageJSON.exports['./*.js'] = './*.js';
packageJSON.exports['./*'] = './*.js';

packageJSON.publishConfig.tag += '-esm';
packageJSON.version += '+esm';
} else {
delete packageJSON.type;
packageJSON.main = 'index';
packageJSON.module = 'index.mjs';
emitTSFiles({ outDir, module: 'commonjs', extension: '.js' });
emitTSFiles({ outDir, module: 'es2020', extension: '.mjs' });
}

// Should be done as the last step so only valid packages can be published
writeGeneratedFile('./npmDist/package.json', JSON.stringify(packageJSON));
writeGeneratedFile(`./${outDir}/package.json`, JSON.stringify(packageJSON));
}

// Based on https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API#getting-the-dts-from-a-javascript-file
function emitTSFiles(outDir: string): {
function emitTSFiles(options: {
outDir: string;
module: string;
extension: string;
}): {
emittedTSFiles: ReadonlyArray<string>;
} {
const { outDir, module, extension } = options;
const tsOptions = readTSConfig({
module: 'es2020',
module,
noEmit: false,
declaration: true,
declarationDir: outDir,
Expand All @@ -108,11 +134,12 @@ function emitTSFiles(outDir: string): {
});

const tsHost = ts.createCompilerHost(tsOptions);
tsHost.writeFile = writeGeneratedFile;
tsHost.writeFile = (filepath, body) =>
writeGeneratedFile(filepath.replace(/.js$/, extension), body);

const tsProgram = ts.createProgram(['src/index.ts'], tsOptions, tsHost);
const tsResult = tsProgram.emit(undefined, undefined, undefined, undefined, {
after: [inlineInvariant],
after: [changeExtensionInImportPaths({ extension }), inlineInvariant],
});
assert(
!tsResult.emitSkipped,
Expand Down
7 changes: 7 additions & 0 deletions resources/integration-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,17 @@ describe('Integration Tests', () => {
});

npm().run('build:npm');

const distDir = localRepoPath('npmDist');
const archiveName = npm({ cwd: tmpDirPath(), quiet: true }).pack(distDir);
fs.renameSync(tmpDirPath(archiveName), tmpDirPath('graphql.tgz'));

const esmDistDir = localRepoPath('npmEsmDist');
const archiveEsmName = npm({ cwd: tmpDirPath(), quiet: true }).pack(
esmDistDir,
);
fs.renameSync(tmpDirPath(archiveEsmName), tmpDirPath('graphql-esm.tgz'));

npm().run('build:deno');

function testOnNodeProject(projectName: string) {
Expand Down
6 changes: 5 additions & 1 deletion resources/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,11 @@ interface PackageJSON {
types?: string;
typesVersions: { [ranges: string]: { [path: string]: Array<string> } };
devDependencies?: { [name: string]: string };
publishConfig?: { tag?: string };
publishConfig: { tag: string };

// TODO: remove after we drop CJS support
main?: string;
module?: string;
}

export function readPackageJSON(
Expand Down

0 comments on commit 87d003d

Please sign in to comment.