Skip to content

Commit

Permalink
fix: keep graphql import as require in cjs (#2258)
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Sep 4, 2024
1 parent 0bc6b3f commit b977602
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 7 deletions.
34 changes: 34 additions & 0 deletions config/plugins/esbuild/graphQLImportPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from 'fs/promises'
import type { Plugin } from 'esbuild'

/**
* A plugin to replace `require('graphql')` statements with `await import('graphql')`
* only for ESM bundles. This makes the GraphQL module to be imported lazily
* while maintaining the CommonJS compatibility.
* @see https://github.com/mswjs/msw/issues/2254
*/
export function graphqlImportPlugin(): Plugin {
return {
name: 'graphql-import-plugin',
setup(build) {
if (build.initialOptions.format !== 'esm') {
return
}

build.onLoad({ filter: /\.ts$/ }, async (args) => {
const contents = await fs.readFile(args.path, 'utf-8')
const match = /require\(['"]graphql['"]\)/g.exec(contents)

if (match) {
return {
loader: 'ts',
contents:
contents.slice(0, match.index - 1) +
`await import('graphql').catch((error) => {console.error('[MSW] Failed to parse a GraphQL query: cannot import the "graphql" module. Please make sure you install it if you wish to intercept GraphQL requests. See the original import error below.'); throw error})` +
contents.slice(match.index + match[0].length),
}
}
})
},
}
}
14 changes: 8 additions & 6 deletions src/core/utils/internal/parseGraphQLRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,14 @@ export function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery {
}

async function parseQuery(query: string): Promise<ParsedGraphQLQuery | Error> {
const { parse } = await import('graphql').catch((error) => {
devUtils.error(
'Failed to parse a GraphQL query: cannot import the "graphql" module. Please make sure you install it if you wish to intercept GraphQL requests. See the original import error below.',
)
throw error
})
/**
* @note Use `require` to get the "graphql" module here.
* It has to be scoped to this function because this module leaks to the
* root export. It has to be `require` because tools like Jest have trouble
* handling dynamic imports. It gets replaced with a dynamic import on build time.
*/
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { parse } = require('graphql')

try {
const ast = parse(query)
Expand Down
3 changes: 2 additions & 1 deletion tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from './config/plugins/esbuild/copyWorkerPlugin'
import { resolveCoreImportsPlugin } from './config/plugins/esbuild/resolveCoreImportsPlugin'
import { forceEsmExtensionsPlugin } from './config/plugins/esbuild/forceEsmExtensionsPlugin'
import { graphqlImportPlugin } from './config/plugins/esbuild/graphQLImportPlugin'
import packageJson from './package.json'

// Externalize the in-house dependencies so that the user
Expand All @@ -33,7 +34,7 @@ const coreConfig: Options = {
sourcemap: true,
dts: true,
tsconfig: path.resolve(__dirname, 'src/tsconfig.core.build.json'),
esbuildPlugins: [forceEsmExtensionsPlugin()],
esbuildPlugins: [graphqlImportPlugin(), forceEsmExtensionsPlugin()],
}

const nodeConfig: Options = {
Expand Down

0 comments on commit b977602

Please sign in to comment.