Mirror: The small sibling of the graphql package, slimmed down for client-side libraries.
1import * as path from 'path'; 2import { promises as fs } from 'fs'; 3 4import resolve from '@rollup/plugin-node-resolve'; 5import replace from '@rollup/plugin-replace'; 6import terser from '@rollup/plugin-terser'; 7import { babel } from '@rollup/plugin-babel'; 8 9import babelModularGraphQL from 'babel-plugin-modular-graphql'; 10import babelTransformComputedProps from '../babel/transformComputedProps.mjs'; 11import babelTransformDevAssert from '../babel/transformDevAssert.mjs'; 12import babelTransformObjectFreeze from '../babel/transformObjectFreeze.mjs'; 13 14import { packageMetadata, version } from './packageMetadata.mjs'; 15import { generateImportMap } from './importMap.mjs'; 16 17const cwd = process.cwd(); 18const graphqlModule = path.posix.join(cwd, 'node_modules/graphql/'); 19const virtualModule = path.posix.join(cwd, 'virtual/'); 20const aliasModule = path.posix.join(cwd, 'alias/'); 21 22const EXTERNAL = 'graphql'; 23const externalModules = ['dns', 'fs', 'path', 'url']; 24const externalPredicate = new RegExp(`^(${externalModules.join('|')})($|/)`); 25 26function manualChunks(id, utils) { 27 let chunk; 28 if (id.startsWith(graphqlModule)) { 29 chunk = id.slice(graphqlModule.length); 30 } else if (id.startsWith(virtualModule)) { 31 chunk = id.slice(virtualModule.length); 32 } else if (id.startsWith(aliasModule)) { 33 chunk = id.slice(aliasModule.length); 34 } 35 36 if (chunk) { 37 return chunk.replace(/\.m?js$/, ''); 38 } 39 40 const { importers } = utils.getModuleInfo(id); 41 return importers.length === 1 ? manualChunks(importers[0], utils) : 'shared'; 42} 43 44function buildPlugin() { 45 const exports = {}; 46 return { 47 async buildStart(options) { 48 const importMap = await generateImportMap(); 49 50 for (const key in importMap) { 51 const { from, local } = importMap[key]; 52 if (/\/jsutils\//g.test(from)) continue; 53 54 const name = from.replace(/^graphql\//, ''); 55 exports[name] = (exports[name] || '') + `export { ${key} } from '${EXTERNAL}'\n`; 56 57 const parts = name.split('/'); 58 for (let i = parts.length - 1; i > 0; i--) { 59 const name = `${parts.slice(0, i).join('/')}/index`; 60 const from = `./${parts.slice(i).join('/')}`; 61 if (from !== './index') 62 exports[name] = (exports[name] || '') + `export { ${local} } from '${from}'\n`; 63 } 64 65 const index = `export { ${local} } from './${name}'\n`; 66 exports.index = (exports.index || '') + index; 67 } 68 69 if (typeof options.input !== 'object') options.input = {}; 70 71 for (const key in exports) { 72 options.input[key] = path.posix.join('./virtual', key); 73 } 74 }, 75 76 async load(id) { 77 if (!id.startsWith(virtualModule)) return null; 78 const entry = path.posix.relative(virtualModule, id).replace(/\.m?js$/, ''); 79 if (entry === 'version') return version; 80 return exports[entry] || null; 81 }, 82 83 async resolveId(source, importer) { 84 if (!source.startsWith('.') && !source.startsWith('virtual/')) return null; 85 86 const target = path.posix.join(importer ? path.posix.dirname(importer) : cwd, source); 87 88 const virtualEntry = path.posix.relative(virtualModule, target); 89 if (!virtualEntry.startsWith('../')) { 90 const aliasSource = path.posix.join(aliasModule, virtualEntry); 91 const alias = await this.resolve(aliasSource, undefined, { 92 skipSelf: true, 93 }); 94 return alias || target; 95 } 96 97 const graphqlEntry = path.posix.relative(graphqlModule, target); 98 if (!graphqlEntry.startsWith('../')) { 99 const aliasSource = path.posix.join(aliasModule, graphqlEntry); 100 const alias = await this.resolve(aliasSource, undefined, { 101 skipSelf: true, 102 }); 103 return alias || target; 104 } 105 106 return null; 107 }, 108 109 async renderStart() { 110 this.emitFile({ 111 type: 'asset', 112 fileName: 'package.json', 113 source: packageMetadata, 114 }); 115 116 this.emitFile({ 117 type: 'asset', 118 fileName: 'README.md', 119 source: await fs.readFile('README.md'), 120 }); 121 122 this.emitFile({ 123 type: 'asset', 124 fileName: 'LICENSE', 125 source: await fs.readFile('./LICENSE.md'), 126 }); 127 }, 128 129 async renderChunk(_code, { fileName }) { 130 const name = fileName.replace(/\.m?js$/, ''); 131 132 const getContents = async extension => { 133 try { 134 const name = fileName.replace(/\.m?js$/, ''); 135 const contents = await fs.readFile(path.join(graphqlModule, name + extension)); 136 return contents; 137 } catch (_error) { 138 return null; 139 } 140 }; 141 142 const dts = await getContents('.d.ts'); 143 const flow = await getContents('.js.flow'); 144 145 if (dts) { 146 this.emitFile({ 147 type: 'asset', 148 fileName: name + '.d.ts', 149 source: dts, 150 }); 151 } 152 153 if (flow) { 154 this.emitFile({ 155 type: 'asset', 156 fileName: name + '.js.flow', 157 source: flow, 158 }); 159 } 160 161 return null; 162 }, 163 }; 164} 165 166export default { 167 input: {}, 168 external(id) { 169 return externalPredicate.test(id); 170 }, 171 treeshake: { 172 unknownGlobalSideEffects: false, 173 tryCatchDeoptimization: false, 174 moduleSideEffects: false, 175 }, 176 plugins: [ 177 buildPlugin(), 178 179 resolve({ 180 extensions: ['.mjs', '.js'], 181 mainFields: ['module', 'browser', 'main'], 182 preferBuiltins: false, 183 browser: true, 184 }), 185 186 babel({ 187 babelrc: false, 188 babelHelpers: 'bundled', 189 presets: [], 190 plugins: [ 191 babelTransformDevAssert, 192 babelTransformObjectFreeze, 193 babelTransformComputedProps, 194 babelModularGraphQL, 195 ], 196 }), 197 198 replace({ 199 preventAssignment: true, 200 values: { 201 'process.env.NODE_ENV': JSON.stringify('production'), 202 }, 203 }), 204 205 terser({ 206 warnings: true, 207 ecma: 2016, 208 keep_fnames: true, 209 compress: { 210 module: true, 211 pure_getters: true, 212 toplevel: true, 213 booleans_as_integers: false, 214 keep_fnames: true, 215 keep_fargs: true, 216 if_return: false, 217 ie8: false, 218 sequences: false, 219 loops: false, 220 conditionals: false, 221 join_vars: false, 222 }, 223 mangle: false, 224 output: { 225 beautify: true, 226 braces: true, 227 indent_level: 2, 228 }, 229 }), 230 ], 231 232 treeshake: 'smallest', 233 shimMissingExports: false, 234 preserveEntrySignatures: 'allow-extension', 235 preserveSymlinks: true, 236 237 output: [ 238 { 239 chunkFileNames: '[name].js', 240 entryFileNames: '[name].js', 241 dir: './dist', 242 exports: 'named', 243 format: 'cjs', 244 minifyInternalExports: false, 245 hoistTransitiveImports: false, 246 manualChunks, 247 }, 248 { 249 chunkFileNames: '[name].mjs', 250 entryFileNames: '[name].mjs', 251 dir: './dist', 252 exports: 'named', 253 format: 'esm', 254 minifyInternalExports: false, 255 hoistTransitiveImports: false, 256 manualChunks, 257 }, 258 ], 259};