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