Mirror: Modular GraphQL.js import paths without the hassle.
1const fs = require('fs'); 2const path = require('path'); 3 4const { rollup } = require('rollup'); 5 6const cwd = process.cwd(); 7const basepath = path.resolve(cwd, 'node_modules/graphql/'); 8 9function generateImportMapPlugin(opts = {}) { 10 const maxDepth = opts.maxDepth || 2; 11 const filename = opts.filename || 'import-map.json'; 12 const map = new Map(); 13 14 const resolveFile = (from, to) => { 15 return path.join(from, to); 16 }; 17 18 const resolveFromMap = (id, name, depth = 0) => { 19 const exports = map.get(id); 20 if (!exports || !exports.has(name)) return null; 21 22 const declaration = exports.get(name); 23 if (depth >= maxDepth || declaration.from === id) { 24 return declaration; 25 } 26 27 return resolveFromMap(declaration.from, declaration.local, depth + 1) || declaration; 28 }; 29 30 return { 31 name: 'generate-import-map', 32 transform(code, id) { 33 const relative = path.relative(basepath, id); 34 const dirname = path.dirname(relative); 35 const exports = new Map(); 36 37 this.parse(code) 38 .body.filter((x) => x.type === 'ExportNamedDeclaration') 39 .forEach((node) => { 40 const source = node.source ? resolveFile(dirname, node.source.value) : relative; 41 42 node.specifiers.forEach((specifier) => { 43 exports.set(specifier.exported.name, { 44 local: specifier.local.name, 45 from: source, 46 }); 47 }); 48 49 if (node.declaration) { 50 (node.declaration.declarations || [node.declaration]).forEach((declaration) => { 51 if (declaration && declaration.id) { 52 const { name } = declaration.id; 53 exports.set(declaration.id.name, { 54 local: name, 55 from: source, 56 }); 57 } 58 }); 59 } 60 }); 61 62 map.set(relative, exports); 63 return null; 64 }, 65 renderChunk(_code, chunk) { 66 const id = chunk.facadeModuleId; 67 const relative = path.relative(basepath, id); 68 69 if (chunk.isEntry) { 70 const importMap = chunk.exports.reduce((acc, name) => { 71 const declaration = resolveFromMap(relative, name); 72 if (declaration) { 73 const dirname = path.join('graphql/', path.dirname(declaration.from)); 74 const filename = path.basename(declaration.from, '.mjs'); 75 76 acc[name] = { 77 local: declaration.local, 78 from: path.join(dirname, filename), 79 }; 80 } 81 82 return acc; 83 }, {}); 84 85 this.emitFile({ 86 type: 'asset', 87 filename, 88 name: filename, 89 source: JSON.stringify(importMap, null, 2), 90 }); 91 } 92 }, 93 }; 94} 95 96(async () => { 97 const bundle = await rollup({ 98 input: path.join(basepath, 'index.mjs'), 99 external: (id) => !/^\.{0,2}\//.test(id), 100 preserveModules: true, 101 plugins: [ 102 require('@rollup/plugin-node-resolve').nodeResolve(), 103 generateImportMapPlugin({ 104 filename: 'import-map.json', 105 }), 106 ], 107 }); 108 109 const { output } = await bundle.generate({}); 110 111 fs.writeFileSync( 112 path.resolve(cwd, 'import-map.json'), 113 output.find((asset) => asset.type === 'asset').source 114 ); 115})().catch((err) => { 116 console.error(`${err.name}: ${err.message}`); 117 process.exit(1); 118});