|
| 1 | +#!/usr/bin/env node |
| 2 | + |
| 3 | +/** |
| 4 | + * Generates examples/graphiql-cdn/index.html |
| 5 | + */ |
| 6 | + |
| 7 | +import fs from 'node:fs'; |
| 8 | +import path from 'node:path'; |
| 9 | +import crypto from 'node:crypto'; |
| 10 | + |
| 11 | +const PACKAGES = [ |
| 12 | + 'react', |
| 13 | + 'react-dom', |
| 14 | + 'graphiql', |
| 15 | + '@graphiql/plugin-explorer', |
| 16 | + '@graphiql/react', |
| 17 | + '@graphiql/toolkit', |
| 18 | + 'graphql', |
| 19 | +]; |
| 20 | + |
| 21 | +async function fetchIntegrityHash(url) { |
| 22 | + const response = await fetch(url, { redirect: 'follow' }); |
| 23 | + if (!response.ok) { |
| 24 | + throw new Error(`Failed to fetch ${url}: ${response.statusText}`); |
| 25 | + } |
| 26 | + const content = await response.text(); |
| 27 | + const hash = crypto.createHash('sha384').update(content).digest('base64'); |
| 28 | + return [url, `sha384-${hash}`]; |
| 29 | +} |
| 30 | + |
| 31 | +async function fetchLatestVersion(packageName) { |
| 32 | + const url = `https://registry.npmjs.org/${packageName}/latest`; |
| 33 | + const response = await fetch(url); |
| 34 | + if (!response.ok) { |
| 35 | + throw new Error(`Failed to fetch ${packageName}: ${response.statusText}`); |
| 36 | + } |
| 37 | + const { version } = await response.json(); |
| 38 | + return [packageName, version] |
| 39 | +} |
| 40 | + |
| 41 | +async function main () { |
| 42 | + const versions = Object.fromEntries(await Promise.all(PACKAGES.map(fetchLatestVersion))); |
| 43 | + const cdnUrl = packageName => `https://esm.sh/${packageName}@${versions[packageName]}`; |
| 44 | + |
| 45 | + // JS |
| 46 | + const imports = { |
| 47 | + 'react': cdnUrl('react'), |
| 48 | + 'react/': `${cdnUrl('react-dom')}/`, |
| 49 | + 'react-dom': cdnUrl('react-dom'), |
| 50 | + 'react-dom/': `${cdnUrl('react-dom')}/`, |
| 51 | + 'graphiql': `${cdnUrl('graphiql')}?standalone&external=react,react-dom,@graphiql/react,graphql`, |
| 52 | + 'graphiql/': `${cdnUrl('graphiql')}/`, |
| 53 | + '@graphiql/plugin-explorer': `${cdnUrl('@graphiql/plugin-explorer')}?standalone&external=react,@graphiql/react,graphql`, |
| 54 | + '@graphiql/react': `${cdnUrl('@graphiql/react')}?standalone&external=react,react-dom,graphql,@graphiql/toolkit,@emotion/is-prop-valid`, |
| 55 | + '@graphiql/toolkit': `${cdnUrl('@graphiql/toolkit')}?standalone&external=graphql`, |
| 56 | + 'graphql': cdnUrl('graphql'), |
| 57 | + '@emotion/is-prop-valid': "data:text/javascript," |
| 58 | + }; |
| 59 | + |
| 60 | + const integrity = Object.fromEntries(await Promise.all([ |
| 61 | + cdnUrl('react'), |
| 62 | + cdnUrl('react-dom'), |
| 63 | + cdnUrl('graphiql'), |
| 64 | + `${cdnUrl('graphiql')}?standalone&external=react,react-dom,@graphiql/react,graphql`, |
| 65 | + cdnUrl('@graphiql/plugin-explorer'), |
| 66 | + `${cdnUrl('@graphiql/react')}?standalone&external=react,react-dom,graphql,@graphiql/toolkit,@emotion/is-prop-valid`, |
| 67 | + `${cdnUrl('@graphiql/toolkit')}?standalone&external=graphql`, |
| 68 | + cdnUrl('graphql'), |
| 69 | + ].map(fetchIntegrityHash))); |
| 70 | + |
| 71 | + const importMap = { imports, integrity }; |
| 72 | + |
| 73 | + // CSS |
| 74 | + const graphiqlCss = `${cdnUrl('graphiql')}/dist/style.css`; |
| 75 | + const graphiqlPluginExplorer = `${cdnUrl('@graphiql/plugin-explorer')}/dist/style.css`; |
| 76 | + |
| 77 | + // Generate index.html |
| 78 | + const templatePath = path.join(import.meta.dirname, '../../resources/index.html.template'); |
| 79 | + const template = fs.readFileSync(templatePath, 'utf8'); |
| 80 | + |
| 81 | + const indent = lines => lines.split('\n').map(line => ` ${line}`).join('\n'); |
| 82 | + |
| 83 | + const output = template |
| 84 | + .replace('{{IMPORTMAP}}', indent(JSON.stringify(importMap, null, 2))) |
| 85 | + .replace('{{GRAPHIQL_CSS_URL}}', graphiqlCss) |
| 86 | + .replace('{{GRAPHIQL_CSS_INTEGRITY}}', (await fetchIntegrityHash(graphiqlCss))[1]) |
| 87 | + .replace('{{PLUGIN_EXPLORER_CSS_URL}}', graphiqlPluginExplorer) |
| 88 | + .replace('{{PLUGIN_EXPLORER_CSS_INTEGRITY}}', (await fetchIntegrityHash(graphiqlPluginExplorer))[1]); |
| 89 | + |
| 90 | + console.log(output); |
| 91 | +} |
| 92 | + |
| 93 | +main(); |
0 commit comments