From d95f52f8e9ba151f3506fc739b2cdb2ad4047499 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 17 Feb 2018 11:15:26 -0500 Subject: [PATCH] fix tests, add WIP dev task --- package.json | 1 + src/cli/dev.ts | 106 ++++++++++++++++++++++++++++++++++++++++++++++ src/cli/export.ts | 1 + src/cli/index.ts | 5 ++- 4 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/cli/dev.ts diff --git a/package.json b/package.json index 0daf922..62df424 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@types/glob": "^5.0.34", "@types/mkdirp": "^0.5.2", "@types/rimraf": "^2.0.2", + "compression": "^1.7.1", "css-loader": "^0.28.7", "electron": "^1.8.2", "eslint": "^4.13.1", diff --git a/src/cli/dev.ts b/src/cli/dev.ts new file mode 100644 index 0000000..5615186 --- /dev/null +++ b/src/cli/dev.ts @@ -0,0 +1,106 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import * as chalk from 'chalk'; +import * as child_process from 'child_process'; +import { create_compilers, create_app, create_routes, create_serviceworker, create_template } from 'sapper/core.js'; + +type Deferred = { + promise?: Promise; + fulfil?: (value: any) => void; + reject?: (err: Error) => void; +} + +function deferred() { + const d: Deferred = {}; + + d.promise = new Promise((fulfil, reject) => { + d.fulfil = fulfil; + d.reject = reject; + }); + + return d; +} + +export default function create_watcher(src: string, dir: string) { + // initial build + const routes = create_routes({ src }); + create_app({ routes, src, dev: true }); + + const compilers = create_compilers(); + + const deferreds = { + client: deferred(), + server: deferred() + }; + + const invalidate = () => Promise.all([ + deferreds.client.promise, + deferreds.server.promise + ]).then(([client_stats, server_stats]) => { + const client_info = client_stats.toJson(); + fs.writeFileSync(path.join(dir, 'stats.client.json'), JSON.stringify(client_info, null, ' ')); + + const server_info = server_stats.toJson(); + fs.writeFileSync(path.join(dir, 'stats.server.json'), JSON.stringify(server_info, null, ' ')); + + const client_files = client_info.assets.map((chunk: { name: string }) => `/client/${chunk.name}`); + + return create_serviceworker({ + routes: create_routes({ src }), + client_files, + src + }); + }); + + function watch_compiler(type: 'client' | 'server', callback: (err: Error) => void) { + const compiler = compilers[type]; + + compiler.plugin('invalid', (filename: string) => { + console.log(chalk.cyan(`${type} bundle invalidated, file changed: ${chalk.bold(filename)}`)); + deferreds[type] = deferred(); + watcher.ready = invalidate(); + }); + + compiler.plugin('failed', (err: Error) => { + deferreds[type].reject(err); + }); + + return compiler.watch({}, (err: Error, stats: any) => { + if (stats.hasErrors()) { + deferreds[type].reject(stats.toJson().errors[0]); + } else { + deferreds[type].fulfil(stats); + } + }); + } + + const chokidar = require('chokidar'); + + function watch_files(pattern: string, callback: () => void) { + const watcher = chokidar.watch(pattern, { + persistent: false + }); + + watcher.on('add', callback); + watcher.on('change', callback); + watcher.on('unlink', callback); + } + + watch_files('routes/**/*.+(html|js|mjs)', () => { + const routes = create_routes({ src }); + create_app({ routes, src, dev: true }); + }); + + watch_files('app/template.html', () => { + const template = create_template(); + // TODO reload current page? + }); + + watch_compiler('client', () => { + + }); + + watch_compiler('server', () => { + + }); +} \ No newline at end of file diff --git a/src/cli/export.ts b/src/cli/export.ts index a60851f..557e32b 100644 --- a/src/cli/export.ts +++ b/src/cli/export.ts @@ -4,6 +4,7 @@ import * as sander from 'sander'; import express from 'express'; import cheerio from 'cheerio'; import URL from 'url-parse'; +import fetch from 'node-fetch'; const { OUTPUT_DIR = 'dist' } = process.env; diff --git a/src/cli/index.ts b/src/cli/index.ts index 93a5290..645d617 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -3,6 +3,7 @@ import chalk from 'chalk'; import help from './help.md'; import build from './build'; import exporter from './export'; +import dev from './dev'; import upgrade from './upgrade'; import { dest, entry, src } from '../config'; import * as pkg from '../../package.json'; @@ -39,7 +40,7 @@ if (cmd === 'build') { }); } else if (cmd === 'export') { build({ dest, dev: false, entry, src }) - .then(() => exporter({ src, dest })) + .then(() => exporter(dest)) .then(() => { const elapsed = Date.now() - start; console.error(`extracted in ${elapsed}ms`); // TODO beautify this, e.g. 'built in 4.7 seconds' @@ -47,6 +48,8 @@ if (cmd === 'build') { .catch(err => { console.error(err ? err.details || err.stack || err.message || err : 'Unknown error'); }); +} else if (cmd === 'dev') { + dev(src, dest); } else if (cmd === 'upgrade') { upgrade(); } else {