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 buble from '@rollup/plugin-buble';
6import replace from '@rollup/plugin-replace';
7import terser from '@rollup/plugin-terser';
8import { babel } from '@rollup/plugin-babel';
9
10import babelModularGraphQL from 'babel-plugin-modular-graphql';
11import babelTransformComputedProps from '../babel/transformComputedProps.mjs';
12import babelTransformDevAssert from '../babel/transformDevAssert.mjs';
13import babelTransformObjectFreeze from '../babel/transformObjectFreeze.mjs';
14
15import { importMap, packageMetadata, version } from './packageMetadata.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
26const exports = {};
27
28for (const key in importMap) {
29 const { from, local } = importMap[key];
30 if (/\/jsutils\//g.test(from)) continue;
31
32 const name = from.replace(/^graphql\//, '');
33 exports[name] = (exports[name] || '') + `export { ${key} } from '${EXTERNAL}'\n`;
34
35 const parts = name.split('/');
36 for (let i = parts.length - 1; i > 0; i--) {
37 const name = `${parts.slice(0, i).join('/')}/index`;
38 const from = `./${parts.slice(i).join('/')}`;
39 exports[name] = (exports[name] || '') + `export { ${local} } from '${from}'\n`;
40 }
41
42 const index = `export { ${local} } from './${name}'\n`;
43 exports.index = (exports.index || '') + index;
44}
45
46const manualChunks = (id, utils) => {
47 let chunk;
48 if (id.startsWith(graphqlModule)) {
49 chunk = id.slice(graphqlModule.length);
50 } else if (id.startsWith(virtualModule)) {
51 chunk = id.slice(virtualModule.length);
52 } else if (id.startsWith(aliasModule)) {
53 chunk = id.slice(aliasModule.length);
54 }
55
56 if (chunk) {
57 return chunk.replace(/\.m?js$/, '');
58 }
59
60 const { importers } = utils.getModuleInfo(id);
61 return importers.length === 1 ? manualChunks(importers[0], utils) : 'shared';
62};
63
64export default {
65 input: Object.keys(exports).reduce((input, key) => {
66 input[key] = path.posix.join('./virtual', key);
67 return input;
68 }, {}),
69 external(id) {
70 return externalPredicate.test(id);
71 },
72 treeshake: {
73 unknownGlobalSideEffects: false,
74 tryCatchDeoptimization: false,
75 moduleSideEffects: false,
76 },
77 plugins: [
78 {
79 async load(id) {
80 if (!id.startsWith(virtualModule)) return null;
81 const entry = path.posix.relative(virtualModule, id).replace(/\.m?js$/, '');
82 if (entry === 'version') return version;
83 return exports[entry] || null;
84 },
85
86 async resolveId(source, importer) {
87 if (!source.startsWith('.') && !source.startsWith('virtual/')) return null;
88
89 const target = path.posix.join(importer ? path.posix.dirname(importer) : cwd, source);
90
91 const virtualEntry = path.posix.relative(virtualModule, target);
92 if (!virtualEntry.startsWith('../')) {
93 const aliasSource = path.posix.join(aliasModule, virtualEntry);
94 const alias = await this.resolve(aliasSource, undefined, {
95 skipSelf: true,
96 });
97 return alias || target;
98 }
99
100 const graphqlEntry = path.posix.relative(graphqlModule, target);
101 if (!graphqlEntry.startsWith('../')) {
102 const aliasSource = path.posix.join(aliasModule, graphqlEntry);
103 const alias = await this.resolve(aliasSource, undefined, {
104 skipSelf: true,
105 });
106 return alias || target;
107 }
108
109 return null;
110 },
111
112 async renderStart() {
113 this.emitFile({
114 type: 'asset',
115 fileName: 'package.json',
116 source: packageMetadata,
117 });
118
119 this.emitFile({
120 type: 'asset',
121 fileName: 'README.md',
122 source: await fs.readFile('README.md'),
123 });
124
125 this.emitFile({
126 type: 'asset',
127 fileName: 'LICENSE',
128 source: await fs.readFile('./LICENSE.md'),
129 });
130 },
131
132 async renderChunk(_code, { fileName }) {
133 const name = fileName.replace(/\.m?js$/, '');
134
135 const getContents = async extension => {
136 try {
137 const name = fileName.replace(/\.m?js$/, '');
138 const contents = await fs.readFile(path.join(graphqlModule, name + extension));
139 return contents;
140 } catch (_error) {
141 return null;
142 }
143 };
144
145 const dts = await getContents('.d.ts');
146 const flow = await getContents('.js.flow');
147
148 if (dts) {
149 this.emitFile({
150 type: 'asset',
151 fileName: name + '.d.ts',
152 source: dts,
153 });
154 }
155
156 if (flow) {
157 this.emitFile({
158 type: 'asset',
159 fileName: name + '.js.flow',
160 source: flow,
161 });
162 }
163
164 return null;
165 },
166 },
167
168 resolve({
169 extensions: ['.mjs', '.js'],
170 mainFields: ['module', 'browser', 'main'],
171 preferBuiltins: false,
172 browser: true,
173 }),
174
175 babel({
176 babelrc: false,
177 babelHelpers: 'bundled',
178 presets: [],
179 plugins: [
180 babelTransformDevAssert,
181 babelTransformObjectFreeze,
182 babelTransformComputedProps,
183 babelModularGraphQL,
184 ],
185 }),
186
187 buble({
188 transforms: {
189 stickyRegExp: false,
190 unicodeRegExp: false,
191 dangerousForOf: true,
192 dangerousTaggedTemplateString: true,
193 asyncAwait: false,
194 },
195 objectAssign: 'Object.assign',
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: 5,
208 keep_fnames: true,
209 ie8: false,
210 compress: {
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: {
224 module: true,
225 keep_fnames: true,
226 },
227 output: {
228 beautify: true,
229 braces: true,
230 indent_level: 2,
231 },
232 }),
233 ],
234
235 treeshake: 'smallest',
236 shimMissingExports: false,
237 preserveEntrySignatures: 'allow-extension',
238
239 output: [
240 {
241 chunkFileNames: '[name].js',
242 entryFileNames: '[name].js',
243 dir: './dist',
244 exports: 'named',
245 format: 'cjs',
246 minifyInternalExports: false,
247 hoistTransitiveImports: false,
248 manualChunks,
249 },
250 {
251 chunkFileNames: '[name].mjs',
252 entryFileNames: '[name].mjs',
253 dir: './dist',
254 exports: 'named',
255 format: 'esm',
256 minifyInternalExports: false,
257 hoistTransitiveImports: false,
258 manualChunks,
259 },
260 ],
261};