@graphql-tools/webpack-loader
Version:
A set of utils for faster development of GraphQL tools
82 lines (81 loc) • 3.15 kB
JavaScript
import os from 'os';
import { isExecutableDefinitionNode, Kind } from 'graphql';
import { optimizeDocumentNode, removeDescriptions, removeEmptyNodes, } from '@graphql-tools/optimize';
import { uniqueCode } from '@graphql-tools/webpack-loader-runtime';
import { parseDocument } from './parser.js';
function isSDL(doc) {
return !doc.definitions.some(def => isExecutableDefinitionNode(def));
}
function expandImports(source, options) {
const lines = source.split(/\r\n|\r|\n/);
let outputCode = options.importHelpers
? `
var useUnique = require('@graphql-tools/webpack-loader-runtime').useUnique;
var unique = useUnique();
`
: `
${uniqueCode}
`;
lines.some(line => {
if (line[0] === '#' && line.slice(1).split(' ')[0] === 'import') {
const importFile = line.slice(1).split(' ')[1];
const parseDocument = `require(${importFile})`;
const appendDef = `doc.definitions = doc.definitions.concat(unique(${parseDocument}.definitions));`;
outputCode += appendDef + os.EOL;
}
return line.length !== 0 && line[0] !== '#';
});
return outputCode;
}
export default function graphqlLoader(source) {
this.cacheable();
// TODO: This should probably use this.getOptions()
const options = this.query || {};
let doc = parseDocument(source);
const optimizers = [];
if (options.noDescription) {
optimizers.push(removeDescriptions);
}
if (options.noEmptyNodes) {
optimizers.push(removeEmptyNodes);
}
if (optimizers.length > 0 && isSDL(doc)) {
doc = optimizeDocumentNode(doc, optimizers);
}
let stringifiedDoc = JSON.stringify(doc);
if (options.replaceKinds) {
for (const identifier in Kind) {
const value = Kind[identifier];
stringifiedDoc = stringifiedDoc.replace(new RegExp(`"kind":"${value}"`, 'g'), `"kind": Kind.${identifier}`);
}
}
const headerCode = `
${options.replaceKinds ? "var Kind = require('graphql/language/kinds');" : ''}
var doc = ${stringifiedDoc};
`;
let outputCode = '';
// Allow multiple query/mutation definitions in a file. This parses out dependencies
// at compile time, and then uses those at load time to create minimal query documents
// We cannot do the latter at compile time due to how the #import code works.
const operationCount = doc.definitions.reduce((accum, op) => {
if (op.kind === Kind.OPERATION_DEFINITION) {
return accum + 1;
}
return accum;
}, 0);
function exportDefaultStatement(identifier) {
if (options.esModule) {
return `export default ${identifier}`;
}
return `module.exports = ${identifier}`;
}
if (operationCount > 1) {
throw new Error('GraphQL Webpack Loader allows only for one GraphQL Operation per file');
}
outputCode += `
${exportDefaultStatement('doc')}
`;
const importOutputCode = expandImports(source, options);
const allCode = [headerCode, importOutputCode, outputCode, ''].join(os.EOL);
return allCode;
}