mirror of
https://github.com/kevin-DL/sapper.git
synced 2026-01-12 03:05:12 +00:00
107 lines
2.8 KiB
TypeScript
107 lines
2.8 KiB
TypeScript
import * as child_process from 'child_process';
|
|
import * as path from 'path';
|
|
import * as sander from 'sander';
|
|
import * as colors from 'ansi-colors';
|
|
import cheerio from 'cheerio';
|
|
import URL from 'url-parse';
|
|
import fetch from 'node-fetch';
|
|
import * as ports from 'port-authority';
|
|
import prettyBytes from 'pretty-bytes';
|
|
import { minify_html } from './utils/minify_html';
|
|
import { locations } from '../config';
|
|
|
|
export async function exporter(export_dir: string, { basepath = '' }) {
|
|
const build_dir = locations.dest();
|
|
|
|
export_dir = path.join(export_dir, basepath);
|
|
|
|
// Prep output directory
|
|
sander.rimrafSync(export_dir);
|
|
|
|
sander.copydirSync('assets').to(export_dir);
|
|
sander.copydirSync(build_dir, 'client').to(export_dir, 'client');
|
|
|
|
if (sander.existsSync(build_dir, 'service-worker.js')) {
|
|
sander.copyFileSync(build_dir, 'service-worker.js').to(export_dir, 'service-worker.js');
|
|
}
|
|
|
|
if (sander.existsSync(build_dir, 'service-worker.js.map')) {
|
|
sander.copyFileSync(build_dir, 'service-worker.js.map').to(export_dir, 'service-worker.js.map');
|
|
}
|
|
|
|
const port = await ports.find(3000);
|
|
|
|
const origin = `http://localhost:${port}`;
|
|
|
|
const proc = child_process.fork(path.resolve(`${build_dir}/server.js`), [], {
|
|
cwd: process.cwd(),
|
|
env: Object.assign({
|
|
PORT: port,
|
|
NODE_ENV: 'production',
|
|
SAPPER_DEST: build_dir,
|
|
SAPPER_EXPORT: 'true'
|
|
}, process.env)
|
|
});
|
|
|
|
const seen = new Set();
|
|
const saved = new Set();
|
|
|
|
proc.on('message', message => {
|
|
if (!message.__sapper__) return;
|
|
|
|
let file = new URL(message.url, origin).pathname.slice(1);
|
|
let { body } = message;
|
|
|
|
if (saved.has(file)) return;
|
|
saved.add(file);
|
|
|
|
const is_html = message.type === 'text/html';
|
|
|
|
if (is_html) {
|
|
file = file === '' ? 'index.html' : `${file}/index.html`;
|
|
body = minify_html(body);
|
|
}
|
|
|
|
console.log(`${colors.bold.cyan(file)} ${colors.gray(`(${prettyBytes(body.length)})`)}`);
|
|
|
|
sander.writeFileSync(export_dir, file, body);
|
|
});
|
|
|
|
async function handle(url: URL) {
|
|
const r = await fetch(url.href);
|
|
const range = ~~(r.status / 100);
|
|
|
|
if (range >= 4) {
|
|
console.log(`${colors.red(`> Received ${r.status} response when fetching ${url.pathname}`)}`);
|
|
return;
|
|
}
|
|
|
|
if (range === 2) {
|
|
if (r.headers.get('Content-Type') === 'text/html') {
|
|
const body = await r.text();
|
|
const $ = cheerio.load(body);
|
|
const urls: URL[] = [];
|
|
|
|
const base = new URL($('base').attr('href') || '/', url.href);
|
|
|
|
$('a[href]').each((i: number, $a) => {
|
|
const url = new URL($a.attribs.href, base.href);
|
|
|
|
if (url.origin === origin && !seen.has(url.pathname)) {
|
|
seen.add(url.pathname);
|
|
urls.push(url);
|
|
}
|
|
});
|
|
|
|
for (const url of urls) {
|
|
await handle(url);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ports.wait(port)
|
|
.then(() => handle(new URL(`/${basepath}`, origin))) // TODO all static routes
|
|
.then(() => proc.kill());
|
|
}
|