references
Last active
February 14, 2021 18:53
-
-
Save RyosukeCla/d184c8ad52b66c9f822bb0d71a7e4cbd to your computer and use it in GitHub Desktop.
generate html from svelte
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as svelte from 'svelte/compiler'; | |
import * as rollup from 'rollup/dist/es/rollup.browser.js'; | |
const PACKAGES_BASE_URL = 'https://unpkg.com'; | |
export async function generateHtmlFromSvelteApp(svelteCode) { | |
const result = await bundleSvelteApp(svelteCode); | |
const code = result.output[0].code; | |
const generateHtml = Function(` | |
${code} | |
const fragment = document.createElement('div'); | |
new SvelteComponent.default({ | |
target: fragment, | |
}); | |
const innerHTML = fragment.innerHTML; | |
fragment.remove(); | |
return innerHTML; | |
`); | |
return generateHtml(); | |
} | |
async function bundleSvelteApp(svelteCode) { | |
const lookups = [ | |
{ | |
resolve: "./App.svelte", | |
code: svelteCode, | |
} | |
]; | |
const whilteList = [ | |
"svelte/internal", | |
] | |
const bundle = await rollup.rollup({ | |
input: './App.svelte', | |
plugins: [ | |
sveltePlugin(lookups), | |
packagesPlugin(whilteList), | |
] | |
}); | |
const bundleResult = await bundle.generate({ | |
format: 'iife', | |
name: 'SvelteComponent', | |
exports: 'named', | |
sourcemap: true | |
}); | |
await bundle.close(); | |
return bundleResult; | |
} | |
function packagesPlugin(whilelist) { | |
const whitelistSet = new Set(whilelist); | |
return { | |
name: 'packagesPlugin', | |
async resolveId(source) { | |
if (!whitelistSet.has(source)) return null; | |
const packageJsonUrl = await followRedirects(`${PACKAGES_BASE_URL}/${source}/package.json`); | |
const packageJsonRes = await fetchIfUncached(packageJsonUrl); | |
const packageJson = JSON.parse(packageJsonRes.body); | |
if (packageJson.svelte || packageJson.module || packageJson.main) { | |
const url = packageJsonUrl.replace('/package.json', ''); | |
return new URL(packageJson.svelte || packageJson.module || packageJson.main, `${url}/`).href; | |
} | |
return await followRedirects(`${PACKAGES_BASE_URL}/${source}`); | |
}, | |
async load(resolveId) { | |
const res = await fetchIfUncached(resolveId); | |
return res.body; | |
}, | |
} | |
} | |
/** | |
* @param {{ resolve: string, code: string }[] } lookups | |
*/ | |
function sveltePlugin(lookups) { | |
const lookupMap = new Map(); | |
lookups.forEach(lookup => { | |
lookupMap.set(lookup.resolve, lookup.code); | |
}) | |
return { | |
name: 'lookupPlugin', | |
async resolveId(source) { | |
if (lookupMap.has(source)) return source; | |
return null; | |
}, | |
async load(resolveId) { | |
if (lookupMap.has(resolveId)) return lookupMap.get(resolveId); | |
return null; | |
}, | |
transform(code, resolveId) { | |
if (!/\.svelte$/.test(resolveId)) return null; | |
const result = svelte.compile(code, { | |
hydratable: true, | |
generate: 'dom', | |
format: 'esm', | |
css: false, | |
}); | |
return result.js; | |
} | |
} | |
} | |
async function followRedirects(url) { | |
const res = await fetchIfUncached(url); | |
return res.url; | |
} | |
const fetch_cache = new Map(); | |
function fetchIfUncached(url) { | |
if (fetch_cache.has(url)) { | |
return fetch_cache.get(url); | |
} | |
const promise = fetch(url) | |
.then(async r => { | |
if (r.ok) { | |
return { | |
url: r.url, | |
body: await r.text() | |
}; | |
} | |
throw new Error(await r.text()); | |
}) | |
.catch(err => { | |
fetch_cache.delete(url); | |
throw err; | |
}); | |
fetch_cache.set(url, promise); | |
return promise; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment