UNPKG

@sveltejs/kit

Version:

Here be dragons, etc etc.

277 lines (218 loc) • 7 kB
'use strict'; var _package = require('./package.js'); var path = require('path'); require('module'); var fs = require('fs'); var Url = require('url'); var utils = require('./utils.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); function clean_html(html) { return html .replace(/<!\[CDATA\[[\s\S]*?\]\]>/gm, '') .replace(/(<script[\s\S]*?>)[\s\S]*?<\/script>/gm, '$1</' + 'script>') .replace(/(<style[\s\S]*?>)[\s\S]*?<\/style>/gm, '$1</' + 'style>') .replace(/<!--[\s\S]*?-->/gm, ''); } function get_href(attrs) { const match = /href\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs); return match && (match[1] || match[2] || match[3]); } function get_src(attrs) { const match = /src\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/.exec(attrs); return match && (match[1] || match[2] || match[3]); } function get_srcset_urls(attrs) { const results = []; // Note that the srcset allows any ASCII whitespace, including newlines. const match = /srcset\s*=\s*(?:"(.*?)"|'(.*?)'|([^\s>]*))/s.exec(attrs); if (match) { const attr_content = match[1] || match[2] || match[3]; // Parse the content of the srcset attribute. // The regexp is modelled after the srcset specs (https://html.spec.whatwg.org/multipage/images.html#srcset-attribute) // and should cover most reasonable cases. const regex = /\s*([^\s,]\S+[^\s,])\s*((?:\d+w)|(?:-?\d+(?:\.\d+)?(?:[eE]-?\d+)?x))?/gm; let sub_matches; while ((sub_matches = regex.exec(attr_content))) { results.push(sub_matches[1]); } } return results; } const OK = 2; const REDIRECT = 3; async function prerender({ dir, out, manifest, log, force }) { const seen = new Set(); const server_root = path.resolve(dir); const app = require(`${server_root}/server/app.js`); async function crawl(path$1) { if (seen.has(path$1)) return; seen.add(path$1); const rendered = await app.render({ host: null, // TODO ??? method: 'GET', headers: {}, path: path$1, body: null, query: new Url.URLSearchParams() }, { only_prerender: !force }); if (rendered) { const response_type = Math.floor(rendered.status / 100); const headers = rendered.headers; const type = headers && headers['content-type']; const is_html = response_type === REDIRECT || type === 'text/html'; const parts = path$1.split('/'); if (is_html && parts[parts.length - 1] !== 'index.html') { parts.push('index.html'); } const file = `${out}${parts.join('/')}`; utils.mkdirp(path.dirname(file)); if (response_type === REDIRECT) { const location = headers['location']; log.warn(`${rendered.status} ${path$1} -> ${location}`); fs__default['default'].writeFileSync( file, `<script>window.location.href=${JSON.stringify(headers['location'])}</script>` ); return; } if (response_type === OK) { log.info(`${rendered.status} ${path$1}`); fs__default['default'].writeFileSync(file, rendered.body); // TODO minify where possible? } else { // TODO should this fail the build? log.error(`${rendered.status} ${path$1}`); } const { dependencies } = rendered; if (dependencies) { for (const path$1 in dependencies) { const result = dependencies[path$1]; const response_type = Math.floor(result.status / 100); const is_html = result.headers['content-type'] === 'text/html'; const parts = path$1.split('/'); if (is_html && parts[parts.length - 1] !== 'index.html') { parts.push('index.html'); } const file = `${out}${parts.join('/')}`; utils.mkdirp(path.dirname(file)); fs__default['default'].writeFileSync(file, result.body); if (response_type === OK) { log.info(`${result.status} ${path$1}`); } else { log.error(`${result.status} ${path$1}`); } } } if (is_html) { const cleaned = clean_html(rendered.body); let match; const pattern = /<(a|img|link|source)\s+([\s\S]+?)>/gm; while ((match = pattern.exec(cleaned))) { let hrefs = []; const element = match[1]; const attrs = match[2]; if (element === 'a' || element === 'link') { hrefs.push(get_href(attrs)); } else { if (element === 'img') { hrefs.push(get_src(attrs)); } hrefs.push(...get_srcset_urls(attrs)); } hrefs = hrefs.filter(Boolean); for (const href of hrefs) { const resolved = Url.resolve(path$1, href); if (resolved[0] !== '/') continue; const parsed = Url.parse(resolved); const parts = parsed.pathname.slice(1).split('/').filter(Boolean); if (parts[parts.length - 1] === 'index.html') parts.pop(); const file_exists = (parsed.pathname.startsWith('/_app/') && fs__default['default'].existsSync(`${dir}/client/${parsed.pathname}`)) || fs__default['default'].existsSync(`${out}${parsed.pathname}`) || fs__default['default'].existsSync(`static${parsed.pathname}`) || fs__default['default'].existsSync(`static${parsed.pathname}/index.html`); if (file_exists) continue; if (parsed.query) ; await crawl(parsed.pathname); } } } } } const entries = manifest.pages.map((page) => page.path).filter(Boolean); for (const entry of entries) { await crawl(entry); } } class Builder { #generated_files; #static_files; #manifest; constructor({ generated_files, static_files, log, manifest }) { this.#generated_files = generated_files; this.#static_files = static_files; this.#manifest = manifest; this.log = log; } copy_client_files(dest) { utils.copy(`${this.#generated_files}/client`, dest, (file) => file[0] !== '.'); } copy_server_files(dest) { utils.copy(`${this.#generated_files}/server`, dest, (file) => file[0] !== '.'); } copy_static_files(dest) { utils.copy(this.#static_files, dest); } async prerender({ force = false, dest }) { await prerender({ out: dest, force, dir: this.#generated_files, manifest: this.#manifest, log: this.log }); } } async function adapt(config) { if (!config.adapter) { throw new Error('No adapter specified'); } if (typeof config.adapter !== 'string') { // TODO throw new Error('Adapter must be a string'); } const log = utils.logger(); console.log(_package.$.bold().cyan(`\n> Using ${config.adapter}`)); const manifest_file = path.resolve('.svelte/build/manifest.cjs'); if (!fs.existsSync(manifest_file)) { throw new Error('Could not find manifest file. Have you run `svelte-kit build`?'); } const manifest = require(manifest_file); const builder = new Builder({ generated_files: '.svelte/build/optimized', static_files: config.paths.static, manifest, log }); const adapter = _package.requireRelative_1(config.adapter); await adapter(builder); log.success('done'); } exports.adapt = adapt; //# sourceMappingURL=index5.js.map