diff --git a/.babelrc-npm.json b/.babelrc-npm.json index 70fd1db5e6..8963ac9526 100644 --- a/.babelrc-npm.json +++ b/.babelrc-npm.json @@ -1,27 +1,10 @@ { + "presets": [ + ["@babel/preset-env", { "modules": false, "targets": { "node": "14" } }] + ], "plugins": [ + ["./resources/add-extension-to-import-paths.js", { "extension": "js" }], "@babel/plugin-transform-typescript", - "./resources/inline-invariant" - ], - "env": { - "cjs": { - "presets": [ - [ - "@babel/preset-env", - { "modules": "commonjs", "targets": { "node": "14" } } - ] - ], - "plugins": [ - ["./resources/add-extension-to-import-paths", { "extension": "js" }] - ] - }, - "mjs": { - "presets": [ - ["@babel/preset-env", { "modules": false, "targets": { "node": "14" } }] - ], - "plugins": [ - ["./resources/add-extension-to-import-paths", { "extension": "mjs" }] - ] - } - } + "./resources/inline-invariant.js" + ] } diff --git a/.eslintrc.yml b/.eslintrc.yml index 89e9672613..7898a7bf45 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -35,7 +35,7 @@ rules: node/no-exports-assign: error node/no-extraneous-import: error node/no-extraneous-require: error - node/no-missing-import: error + node/no-missing-import: [error, { allowModules: ['graphql'] }] node/no-missing-require: error node/no-new-require: error node/no-path-concat: error @@ -81,7 +81,7 @@ rules: # Static analysis # https://github.com/benmosher/eslint-plugin-import#static-analysis - import/no-unresolved: error + import/no-unresolved: [error, { ignore: ['graphql'] }] import/named: error import/default: error import/namespace: error @@ -671,23 +671,24 @@ overrides: import/no-extraneous-dependencies: [error, { devDependencies: true }] import/no-nodejs-modules: off - files: 'integrationTests/*/**' + parserOptions: + sourceType: module env: node: true rules: node/no-sync: off - node/no-missing-require: [error, { allowModules: ['graphql'] }] - import/no-commonjs: off import/no-nodejs-modules: off no-console: off - files: 'benchmark/**' + parserOptions: + sourceType: module env: node: true rules: internal-rules/only-ascii: [error, { allowEmoji: true }] node/no-sync: off - node/no-missing-require: off + import/no-unresolved: off import/no-nodejs-modules: off - import/no-commonjs: off no-console: off no-await-in-loop: off - files: 'resources/**' @@ -730,3 +731,6 @@ overrides: # Ignore docusarus related webpack aliases import/no-unresolved: ['error', { 'ignore': ['^@theme', '^@docusaurus', '^@generated'] }] + - files: 'benchmark/benchmark.js' + parserOptions: + sourceType: script diff --git a/benchmark/benchmark.js b/benchmark/benchmark.js index 9288d1f273..1475d69da0 100644 --- a/benchmark/benchmark.js +++ b/benchmark/benchmark.js @@ -58,12 +58,21 @@ function prepareBenchmarkProjects(revisionList) { path.join(projectPath, 'package.json'), '{ "private": true }', ); - exec( - 'npm --quiet install --ignore-scripts ' + prepareNPMPackage(revision), - { cwd: projectPath }, - ); exec(`cp -R ${localDir('benchmark')} ${projectPath}`); + const packageJSON = { + private: true, + type: 'module', + dependencies: { + graphql: prepareNPMPackage(revision), + }, + }; + fs.writeFileSync( + path.join(projectPath, 'package.json'), + JSON.stringify(packageJSON, null, 2), + ); + exec('npm --quiet install --ignore-scripts ', { cwd: projectPath }); + return { revision, projectPath }; }); @@ -334,21 +343,21 @@ function grey(str) { function sampleModule(modulePath) { const sampleCode = ` - const assert = require('assert'); - + import assert from 'assert'; assert(global.gc); assert(process.send); - const module = require('${modulePath}'); - clock(7, module.measure); // warm up + import { benchmark } from '${modulePath}'; + + clock(7, benchmark.measure); // warm up global.gc(); process.nextTick(() => { const memBaseline = process.memoryUsage().heapUsed; - const clocked = clock(module.count, module.measure); + const clocked = clock(benchmark.count, benchmark.measure); process.send({ - name: module.name, - clocked: clocked / module.count, - memUsed: (process.memoryUsage().heapUsed - memBaseline) / module.count, + name: benchmark.name, + clocked: clocked / benchmark.count, + memUsed: (process.memoryUsage().heapUsed - memBaseline) / benchmark.count, }); }); @@ -369,6 +378,7 @@ function sampleModule(modulePath) { '--no-concurrent-sweeping', '--predictable', '--expose-gc', + '--input-type=module', '--eval', sampleCode, ], diff --git a/benchmark/buildASTSchema-benchmark.js b/benchmark/buildASTSchema-benchmark.js index b578d71a7f..10e0bcec33 100644 --- a/benchmark/buildASTSchema-benchmark.js +++ b/benchmark/buildASTSchema-benchmark.js @@ -1,13 +1,11 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { buildASTSchema } from 'graphql/utilities/buildASTSchema.js'; -const { parse } = require('graphql/language/parser.js'); -const { buildASTSchema } = require('graphql/utilities/buildASTSchema.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const schemaAST = parse(bigSchemaSDL); -module.exports = { +export const benchmark = { name: 'Build Schema from AST', count: 10, measure() { diff --git a/benchmark/buildClientSchema-benchmark.js b/benchmark/buildClientSchema-benchmark.js index 240c9ca1f1..a3e8723726 100644 --- a/benchmark/buildClientSchema-benchmark.js +++ b/benchmark/buildClientSchema-benchmark.js @@ -1,10 +1,8 @@ -'use strict'; +import { buildClientSchema } from 'graphql/utilities/buildClientSchema.js'; -const { buildClientSchema } = require('graphql/utilities/buildClientSchema.js'); +import { bigSchemaIntrospectionResult } from './fixtures.js'; -const { bigSchemaIntrospectionResult } = require('./fixtures.js'); - -module.exports = { +export const benchmark = { name: 'Build Schema from Introspection', count: 10, measure() { diff --git a/benchmark/fixtures.js b/benchmark/fixtures.js index d057a80526..c4a080713a 100644 --- a/benchmark/fixtures.js +++ b/benchmark/fixtures.js @@ -1,13 +1,10 @@ -'use strict'; +import fs from 'fs'; -const fs = require('fs'); -const path = require('path'); - -exports.bigSchemaSDL = fs.readFileSync( - path.join(__dirname, 'github-schema.graphql'), +export const bigSchemaSDL = fs.readFileSync( + new URL('github-schema.graphql', import.meta.url), 'utf8', ); -exports.bigSchemaIntrospectionResult = JSON.parse( - fs.readFileSync(path.join(__dirname, 'github-schema.json'), 'utf8'), +export const bigSchemaIntrospectionResult = JSON.parse( + fs.readFileSync(new URL('github-schema.json', import.meta.url), 'utf8'), ); diff --git a/benchmark/introspectionFromSchema-benchmark.js b/benchmark/introspectionFromSchema-benchmark.js index 125ca9c367..d5100e267b 100644 --- a/benchmark/introspectionFromSchema-benchmark.js +++ b/benchmark/introspectionFromSchema-benchmark.js @@ -1,20 +1,16 @@ -'use strict'; +import { executeSync } from 'graphql/execution/execute.js'; +import { parse } from 'graphql/language/parser.js'; +import { buildSchema } from 'graphql/utilities/buildASTSchema.js'; +import { getIntrospectionQuery } from 'graphql/utilities/getIntrospectionQuery.js'; -const { parse } = require('graphql/language/parser.js'); -const { executeSync } = require('graphql/execution/execute.js'); -const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); -const { - getIntrospectionQuery, -} = require('graphql/utilities/getIntrospectionQuery.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); const document = parse(getIntrospectionQuery()); -module.exports = { +export const benchmark = { name: 'Execute Introspection Query', - count: 10, + count: 30, measure() { executeSync({ schema, document }); }, diff --git a/benchmark/parser-benchmark.js b/benchmark/parser-benchmark.js index 7f2e7931eb..5a2bfd39da 100644 --- a/benchmark/parser-benchmark.js +++ b/benchmark/parser-benchmark.js @@ -1,13 +1,9 @@ -'use strict'; - -const { parse } = require('graphql/language/parser.js'); -const { - getIntrospectionQuery, -} = require('graphql/utilities/getIntrospectionQuery.js'); +import { parse } from 'graphql/language/parser.js'; +import { getIntrospectionQuery } from 'graphql/utilities/getIntrospectionQuery.js'; const introspectionQuery = getIntrospectionQuery(); -module.exports = { +export const benchmark = { name: 'Parse introspection query', count: 1000, measure() { diff --git a/benchmark/validateGQL-benchmark.js b/benchmark/validateGQL-benchmark.js index cc60a7ade0..6bce5032c8 100644 --- a/benchmark/validateGQL-benchmark.js +++ b/benchmark/validateGQL-benchmark.js @@ -1,18 +1,14 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { buildSchema } from 'graphql/utilities/buildASTSchema.js'; +import { getIntrospectionQuery } from 'graphql/utilities/getIntrospectionQuery.js'; +import { validate } from 'graphql/validation/validate.js'; -const { parse } = require('graphql/language/parser.js'); -const { validate } = require('graphql/validation/validate.js'); -const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); -const { - getIntrospectionQuery, -} = require('graphql/utilities/getIntrospectionQuery.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); const queryAST = parse(getIntrospectionQuery()); -module.exports = { +export const benchmark = { name: 'Validate Introspection Query', count: 50, measure() { diff --git a/benchmark/validateInvalidGQL-benchmark.js b/benchmark/validateInvalidGQL-benchmark.js index 1e44b48914..68666c9211 100644 --- a/benchmark/validateInvalidGQL-benchmark.js +++ b/benchmark/validateInvalidGQL-benchmark.js @@ -1,10 +1,8 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { buildSchema } from 'graphql/utilities/buildASTSchema.js'; +import { validate } from 'graphql/validation/validate.js'; -const { parse } = require('graphql/language/parser.js'); -const { validate } = require('graphql/validation/validate.js'); -const { buildSchema } = require('graphql/utilities/buildASTSchema.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const schema = buildSchema(bigSchemaSDL, { assumeValid: true }); const queryAST = parse(` @@ -21,7 +19,7 @@ const queryAST = parse(` } `); -module.exports = { +export const benchmark = { name: 'Validate Invalid Query', count: 50, measure() { diff --git a/benchmark/validateSDL-benchmark.js b/benchmark/validateSDL-benchmark.js index 93c80bbc56..75466ee83d 100644 --- a/benchmark/validateSDL-benchmark.js +++ b/benchmark/validateSDL-benchmark.js @@ -1,13 +1,11 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { validateSDL } from 'graphql/validation/validate.js'; -const { parse } = require('graphql/language/parser.js'); -const { validateSDL } = require('graphql/validation/validate.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const sdlAST = parse(bigSchemaSDL); -module.exports = { +export const benchmark = { name: 'Validate SDL Document', count: 10, measure() { diff --git a/benchmark/visit-benchmark.js b/benchmark/visit-benchmark.js index ab6a2baac2..528f7c6981 100644 --- a/benchmark/visit-benchmark.js +++ b/benchmark/visit-benchmark.js @@ -1,9 +1,7 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { visit } from 'graphql/language/visitor.js'; -const { parse } = require('graphql/language/parser.js'); -const { visit } = require('graphql/language/visitor.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const documentAST = parse(bigSchemaSDL); @@ -16,7 +14,7 @@ const visitor = { }, }; -module.exports = { +export const benchmark = { name: 'Visit all AST nodes', count: 10, measure() { diff --git a/benchmark/visitInParallel-benchmark.js b/benchmark/visitInParallel-benchmark.js index cd835dd19c..dc4cfb42ca 100644 --- a/benchmark/visitInParallel-benchmark.js +++ b/benchmark/visitInParallel-benchmark.js @@ -1,9 +1,7 @@ -'use strict'; +import { parse } from 'graphql/language/parser.js'; +import { visit, visitInParallel } from 'graphql/language/visitor.js'; -const { parse } = require('graphql/language/parser.js'); -const { visit, visitInParallel } = require('graphql/language/visitor.js'); - -const { bigSchemaSDL } = require('./fixtures.js'); +import { bigSchemaSDL } from './fixtures.js'; const documentAST = parse(bigSchemaSDL); @@ -16,7 +14,7 @@ const visitors = new Array(50).fill({ }, }); -module.exports = { +export const benchmark = { name: 'Visit all AST nodes in parallel', count: 10, measure() { diff --git a/integrationTests/node/index.js b/integrationTests/node/index.js index 4815fe52e4..3b39900906 100644 --- a/integrationTests/node/index.js +++ b/integrationTests/node/index.js @@ -1,10 +1,10 @@ -'use strict'; +/* eslint-disable simple-import-sort/imports */ +import assert from 'assert'; +import { readFileSync } from 'fs'; -const assert = require('assert'); -const { readFileSync } = require('fs'); - -const { version, graphqlSync } = require('graphql'); -const { buildSchema } = require('graphql/utilities'); +import { graphqlSync } from 'graphql'; +import { buildSchema } from 'graphql/utilities'; +import { version } from 'graphql/version'; assert.deepStrictEqual( version, diff --git a/integrationTests/node/package.json b/integrationTests/node/package.json index e4e8d36d97..2d2665ed9a 100644 --- a/integrationTests/node/package.json +++ b/integrationTests/node/package.json @@ -1,6 +1,7 @@ { "private": true, "description": "graphql-js should work on all supported node versions", + "type": "module", "scripts": { "test": "node test.js" }, diff --git a/integrationTests/node/test.js b/integrationTests/node/test.js index 3f9ea8d35e..e3e55bb745 100644 --- a/integrationTests/node/test.js +++ b/integrationTests/node/test.js @@ -1,8 +1,9 @@ -'use strict'; +import childProcess from 'child_process'; +import fs from 'fs'; -const childProcess = require('child_process'); - -const graphqlPackageJSON = require('graphql/package.json'); +const graphqlPackageJSON = JSON.parse( + fs.readFileSync('./node_modules/graphql/package.json', 'utf-8'), +); const nodeVersions = graphqlPackageJSON.engines.node .split(' || ') diff --git a/integrationTests/ts/package.json b/integrationTests/ts/package.json index 51f768dad6..6a02fd76af 100644 --- a/integrationTests/ts/package.json +++ b/integrationTests/ts/package.json @@ -1,6 +1,7 @@ { "private": true, "description": "graphql-js should compile with all supported TS versions", + "type": "module", "scripts": { "test": "node test.js" }, diff --git a/integrationTests/ts/test.js b/integrationTests/ts/test.js index b328fe160b..0d0fb81cbc 100644 --- a/integrationTests/ts/test.js +++ b/integrationTests/ts/test.js @@ -1,9 +1,8 @@ -'use strict'; +import childProcess from 'child_process'; +import fs from 'fs'; +import path from 'path'; -const path = require('path'); -const childProcess = require('child_process'); - -const { dependencies } = require('./package.json'); +const { dependencies } = JSON.parse(fs.readFileSync('./package.json', 'utf-8')); const tsVersions = Object.keys(dependencies) .filter((pkg) => pkg.startsWith('typescript-')) @@ -15,5 +14,5 @@ for (const version of tsVersions) { } function tscPath(version) { - return path.join(__dirname, 'node_modules', version, 'bin/tsc'); + return path.join('node_modules', version, 'bin', 'tsc'); } diff --git a/integrationTests/webpack/entry.js b/integrationTests/webpack/entry.js index 8f51030c5d..5254922cbf 100644 --- a/integrationTests/webpack/entry.js +++ b/integrationTests/webpack/entry.js @@ -1,13 +1,9 @@ -'use strict'; - -const { buildSchema, graphqlSync } = require('graphql'); +import { buildSchema, graphqlSync } from 'graphql'; const schema = buildSchema('type Query { hello: String }'); -const result = graphqlSync({ +export const result = graphqlSync({ schema, source: '{ hello }', rootValue: { hello: 'world' }, }); - -module.exports = { result }; diff --git a/integrationTests/webpack/package.json b/integrationTests/webpack/package.json index aec7a21afb..74a2502ff7 100644 --- a/integrationTests/webpack/package.json +++ b/integrationTests/webpack/package.json @@ -1,6 +1,7 @@ { "private": true, "description": "graphql-js should be compatible with Webpack", + "type": "module", "scripts": { "test": "webpack && node test.js" }, diff --git a/integrationTests/webpack/test.js b/integrationTests/webpack/test.js index 40c22233d4..b3b19410cf 100644 --- a/integrationTests/webpack/test.js +++ b/integrationTests/webpack/test.js @@ -1,11 +1,9 @@ -'use strict'; +import assert from 'assert'; -const assert = require('assert'); +// eslint-disable-next-line import/no-unresolved, node/no-missing-import +import mainCJS from './dist/main.cjs'; -// eslint-disable-next-line node/no-missing-require -const { result } = require('./dist/main.js'); - -assert.deepStrictEqual(result, { +assert.deepStrictEqual(mainCJS.result, { data: { __proto__: null, hello: 'world', diff --git a/integrationTests/webpack/webpack.config.json b/integrationTests/webpack/webpack.config.json index 830b2bd52d..4d3276186c 100644 --- a/integrationTests/webpack/webpack.config.json +++ b/integrationTests/webpack/webpack.config.json @@ -2,6 +2,9 @@ "mode": "production", "entry": "./entry.js", "output": { - "libraryTarget": "commonjs2" + "filename": "main.cjs", + "library": { + "type": "commonjs2" + } } } diff --git a/package.json b/package.json index 7b90fe1d97..df0e4caaf1 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,6 @@ "description": "A Query Language and Runtime which can target any service.", "license": "MIT", "private": true, - "main": "index", - "module": "index.mjs", "typesVersions": { ">=4.4.0": { "*": [ diff --git a/resources/build-npm.js b/resources/build-npm.js index 7ff0cf079c..d20352dc8f 100644 --- a/resources/build-npm.js +++ b/resources/build-npm.js @@ -20,17 +20,25 @@ if (require.main === module) { const packageJSON = buildPackageJSON(); const srcFiles = readdirRecursive('./src', { ignoreDir: /^__.*__$/ }); - for (const filepath of srcFiles) { - const srcPath = path.join('./src', filepath); - const destPath = path.join('./npmDist', filepath); + for (const srcFilePath of srcFiles) { + if (srcFilePath.endsWith('.ts')) { + const destFilePath = srcFilePath.replace(/\.ts$/, '.js'); - fs.mkdirSync(path.dirname(destPath), { recursive: true }); - if (filepath.endsWith('.ts')) { - const cjs = babelBuild(srcPath, { envName: 'cjs' }); - writeGeneratedFile(destPath.replace(/\.ts$/, '.js'), cjs); + const srcPath = path.join('./src', srcFilePath); + const destPath = path.join('./npmDist', destFilePath); - const mjs = babelBuild(srcPath, { envName: 'mjs' }); - writeGeneratedFile(destPath.replace(/\.ts$/, '.mjs'), mjs); + fs.mkdirSync(path.dirname(destPath), { recursive: true }); + + const { code } = babel.transformFileSync(srcPath, { + babelrc: false, + configFile: './.babelrc-npm.json', + }); + writeGeneratedFile(destPath, code + '\n'); + + if (path.basename(destFilePath) === 'index.js') { + const key = destFilePath.replace(/\/index.js$/, ''); + packageJSON.exports[key] = destFilePath; + } } } @@ -89,15 +97,6 @@ if (require.main === module) { showDirStats('./npmDist'); } -function babelBuild(srcPath, options) { - const { code } = babel.transformFileSync(srcPath, { - babelrc: false, - configFile: './.babelrc-npm.json', - ...options, - }); - return code + '\n'; -} - function buildPackageJSON() { const packageJSON = JSON.parse( fs.readFileSync(require.resolve('../package.json'), 'utf-8'), @@ -107,6 +106,13 @@ function buildPackageJSON() { delete packageJSON.scripts; delete packageJSON.devDependencies; + packageJSON.type = 'module'; + // Temporary workaround to allow "internal" imports, no grantees provided + packageJSON.exports = { + './*.js': './*.js', + './*': './*.js', + }; + // TODO: move to integration tests const publishTag = packageJSON.publishConfig?.tag; assert(publishTag != null, 'Should have packageJSON.publishConfig defined!'); diff --git a/resources/utils.js b/resources/utils.js index 37cd83e801..aa4be2c1ce 100644 --- a/resources/utils.js +++ b/resources/utils.js @@ -33,7 +33,7 @@ function readdirRecursive(dirPath, opts = {}) { ); result.push(...list); } - return result; + return result.map((filepath) => './' + filepath); } function showDirStats(dirPath) {