UNPKG

edge-mock

Version:

types for testing an developer edge applications

282 lines 10.4 kB
#!/usr/bin/env node "use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const express_1 = __importDefault(require("express")); const webpack_1 = __importDefault(require("webpack")); const livereload_1 = __importDefault(require("livereload")); const index_1 = require("./index"); const live_fetch_1 = __importDefault(require("./live_fetch")); const utils_1 = require("./utils"); const default_prepare_key = (f) => f.replace(/.*?dist\/assets\//, ''); function pathExists(path) { return fs_1.default.promises .access(path, fs_1.default.constants.F_OK) .then(() => true) .catch(() => false); } async function load_config() { const cwd = process.cwd(); const dev_server_config = path_1.default.join(cwd, 'edge-mock-config.js'); let config = {}; if (await pathExists(dev_server_config)) { try { config = await Promise.resolve().then(() => __importStar(require(dev_server_config))); console.log('edge-mock-config.js found, using it for config'); } catch (e) { console.error('error loading', dev_server_config, e); } } else { console.log('edge-mock-config.js not found, using default config'); } config.webpack_config = config.webpack_config || path_1.default.join(cwd, 'webpack.config'); config.dist_path = config.dist_path || path_1.default.join(cwd, 'dist/worker'); config.dist_assets_path = config.dist_assets_path || path_1.default.join(cwd, 'dist/assets'); config.prepare_key = config.prepare_key || default_prepare_key; config.port = config.port || 3000; if (!('livereload' in config)) { config.livereload = true; } config.livereload_port = config.livereload_port || 35729; return config; } class WebpackState { _error = null; get error() { return this._error; } clearError() { this._error = null; } setError(err) { this._error = err; } } async function start_webpack(config) { let static_content_kv; const env = index_1.makeEdgeEnv({ fetch: live_fetch_1.default }); const webpack_state = new WebpackState(); async function on_webpack_success(stats) { console.log(stats.toString('minimal')); delete require.cache[require.resolve(config.dist_path)]; if (await pathExists(config.dist_assets_path)) { if (!static_content_kv) { static_content_kv = new index_1.EdgeKVNamespace(); global.__STATIC_CONTENT = static_content_kv; console.log('adding KV store "__STATIC_CONTENT" to global namespace'); } await static_content_kv._add_files(config.dist_assets_path, config.prepare_key); global.__STATIC_CONTENT_MANIFEST = static_content_kv._manifestJson(); } env.clearEventListener(); try { await Promise.resolve().then(() => __importStar(require(config.dist_path))); } catch (err) { webpack_state.setError(err); return; } webpack_state.clearError(); } const wp_config = await Promise.resolve().then(() => __importStar(require(config.webpack_config))); webpack_1.default(wp_config.default).watch({}, (err, stats) => { if (err) { console.error(err); webpack_state.setError(err); } else { on_webpack_success(stats); } }); return [env, webpack_state]; } function livereload_script(config) { if (config.livereload) { return `\n\n<script src="http://localhost:${config.livereload_port}/livereload.js?snipver=1"></script>\n`; } else { return ''; } } class ErrorResponse { response; config; html_template = `<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>{status} Error</title> <meta name="description" content="{message}" /> <style> body { display: flex; color: #24292e; justify-content: center; margin: 40px 10px 60px; font-size: 16px; font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } main { width: min(calc(100vw - 20px), 902px); box-sizing: border-box; border: 1px solid #e1e4e8; border-radius: 6px; padding: 20px 15px 20px; word-wrap: break-word; min-height: 400px; } aside { font-size: 0.9rem; color: #666; } pre code { font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace; background: #f6f8fa; border-radius: 6px; padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; display: block; } </style> </head> <body> <main> <h1>Error</h1> <p><b>{message}</b></p> {detail} <h2>Config:</h2> <pre><code>{config}</code></pre> <aside> (This page is shown by <a href="https://github.com/samuelcolvin/edge-mock#development-server" target="_blank">edge-mock-server</a>, it's a summary of an error that occurred while trying to serve the above web-worker application.) </aside> </main> </body> </html>{livereload} `; constructor(response, config) { this.response = response; this.config = config; } onError(message, error, status = 502) { this.response.status(status); this.response.set({ 'content-type': 'text/html' }); const context = { message: this.escape(message), status: status.toString(), detail: '', livereload: livereload_script(this.config), config: this.escape(JSON.stringify(this.config, null, 2)), }; if (error) { const stack = error.stack?.toString().replace(/\n.*(\/express\/lib\/|edge-mock\/server)(.|\n)*/, ''); context.detail = `<pre><code>${this.escape(error.message)}\n${this.escape(stack || '')}</code></pre>`; console.error(`${message}\n${error.message}\n${stack || ''}`); } else { console.error(message); } let html = this.html_template; for (const [key, value] of Object.entries(context)) { html = html.replace(new RegExp(`{${key}}`, 'g'), value); } this.response.send(html); } escape(s) { const html_tags = { '&': '&amp;', '<': '&lt;', '>': '&gt;' }; return s.replace(/[&<>]/g, letter => html_tags[letter] || letter); } } function run_server(config, env, webpack_state) { const app = express_1.default(); if (config.livereload) { const reload_server = livereload_1.default.createServer({ delay: 300, port: config.livereload_port }); reload_server.watch(path_1.default.dirname(config.dist_path)); } const reload_html = utils_1.encode(livereload_script(config)); app.all(/.*/, (req, res) => { const error_handler = new ErrorResponse(res, config); if (webpack_state.error) { error_handler.onError('Failed to load worker code', webpack_state.error); return; } let listener; try { listener = env.getListener(); } catch (err) { error_handler.onError(err.message); return; } const { url, method, headers } = req; const request = new Request(url, { method, headers: headers }); const event = new FetchEvent('fetch', { request }); event.respondWith = promise => { Promise.resolve(promise) .then(response => { res.status(response.status); res.set(Object.fromEntries(response.headers.entries())); response.arrayBuffer().then(ab => { let body = ab; if (config.livereload && (response.headers.get('content-type') || '').includes('text/html')) { body = utils_1.catArraysBufferViews([new Uint8Array(ab), reload_html]); } res.send(Buffer.from(body)); }); }) .catch(err => error_handler.onError('Internal Error awaiting response promise', err)); }; try { Promise.resolve(listener(event)).catch(err => error_handler.onError('Internal Error running web-worker', err)); } catch (err) { error_handler.onError('Internal Error running web-worker', err); } }); app.listen(config.port, () => { console.log(`dev app running at http://localhost:${config.port}, livereload: ${config.livereload}`); }); } async function main() { const config = await load_config(); // console.log('starting webpack, config: %o', config) const [env, wps] = await start_webpack(config); await run_server(config, env, wps); } if (require.main === module) { main().catch(e => { console.error(e); process.exit(1); }); } //# sourceMappingURL=server.js.map