Skip to content
代码片段 群组 项目
提交 1e23bad3 编辑于 作者: Paul Slaughter's avatar Paul Slaughter
浏览文件

Add evaluateModuleFromSource for gql known op plugin

- Previously we were regexing the source code
- Now we can actually run this module and retrieve from it's export
上级 31b36dcf
No related branches found
No related tags found
无相关合并请求
const vm = require('vm');
/**
* This function uses Node's `vm` modules to evaluate the `module.exports` of a given source string
*
* Example:
*
* ```javascript
* const { exports: moduleExports } = evaluateModuleFromSource("const foo = 7;\n module.exports.bar = 10 + foo;");
*
* assert(moduleExports.bar === 17);
* ```
*
* @param {String} source to be evaluated using Node's `vm` modules
* @param {{ require: Function }} options used in the context during evaluation of the Node module
* @returns {{ exports: any }} exports added to the script's `module.exports` context
*/
const evaluateModuleFromSource = (source, { require } = {}) => {
const context = {
module: {
exports: {},
},
require,
};
try {
const script = new vm.Script(source);
script.runInNewContext(context);
} catch (e) {
console.error(e);
throw e;
}
return context.module;
};
module.exports = { evaluateModuleFromSource };
/* eslint-disable no-underscore-dangle */ /* eslint-disable no-underscore-dangle */
const yaml = require('js-yaml'); const yaml = require('js-yaml');
const { evaluateModuleFromSource } = require('../helpers/evaluate_module_from_source');
const PLUGIN_NAME = 'GraphqlKnownOperationsPlugin'; const PLUGIN_NAME = 'GraphqlKnownOperationsPlugin';
const GRAPHQL_PATH_REGEX = /(query|mutation)\.graphql$/; const GRAPHQL_PATH_REGEX = /(query|mutation)\.graphql$/;
const OPERATION_NAME_SOURCE_REGEX = /^\s*module\.exports.*oneQuery.*"(\w+)"/gm;
/** /**
* Returns whether a given webpack module is a "graphql" module * Returns whether a given webpack module is a "graphql" module
...@@ -26,9 +27,19 @@ const getOperationNames = (module) => { ...@@ -26,9 +27,19 @@ const getOperationNames = (module) => {
return []; return [];
} }
const matches = originalSource.source().toString().matchAll(OPERATION_NAME_SOURCE_REGEX); const { exports: moduleExports } = evaluateModuleFromSource(originalSource.source().toString(), {
// what: stub require(...) when evaluating the graphql module
// why: require(...) is used to fetch fragments. We only need operation metadata, so it's fine to stub these out.
require: () => ({ definitions: [] }),
});
const names = moduleExports.definitions
.filter((x) => ['query', 'mutation'].includes(x.operation))
.map((x) => x.name?.value)
// why: It's possible for operations to not have a name. That violates our eslint rule, but either way, let's ignore those here.
.filter(Boolean);
return Array.from(matches).map((match) => match[1]); return names;
}; };
const createFileContents = (knownOperations) => { const createFileContents = (knownOperations) => {
...@@ -60,7 +71,7 @@ const onSucceedModule = ({ module, knownOperations }) => { ...@@ -60,7 +71,7 @@ const onSucceedModule = ({ module, knownOperations }) => {
return; return;
} }
getOperationNames(module).forEach((x) => knownOperations.add(x)); getOperationNames(module).forEach((name) => knownOperations.add(name));
}; };
const onCompilerEmit = ({ compilation, knownOperations, filename }) => { const onCompilerEmit = ({ compilation, knownOperations, filename }) => {
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册