Skip to content

Commit

Permalink
feat: dev server
Browse files Browse the repository at this point in the history
  • Loading branch information
ikkz committed Dec 5, 2024
1 parent d183c95 commit 6ad518b
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 66 deletions.
28 changes: 1 addition & 27 deletions build/cli.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#!/usr/bin/env node
import { rollupOptions } from './rollup.js';
import { readJson } from './utils.js';
import Koa from 'koa';
import { extname } from 'node:path';
import { parseArgs } from 'node:util';
import { rollup } from 'rollup';
import { watch } from 'rollup';
Expand Down Expand Up @@ -42,39 +40,15 @@ if (!args.dev) {
locale: args.locale,
dev: true,
});
let html = '';
const koa = new Koa();
koa.use(async (ctx) => {
ctx.body = html;
});
koa.listen(3000);
console.log('listen 3000');
const watcher = watch({
...inputOptions,
output: outputOptions,
watch: {
buildDelay: 1000,
clearScreen: false,
exclude: ['node_modules/**', 'dist/**'],
skipWrite: true,
},
});
watcher.on('event', (args) => {
if (args.code === 'BUNDLE_END') {
console.log('BUNDLE_END');
args.result.generate(outputOptions).then(({ output }) => {
html =
'<!DOCTYPE html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>';
output.reverse().forEach((file) => {
if (
extname(file.fileName) === '.html' &&
!file.fileName.endsWith('back.html')
) {
html += file.source;
}
});
});
}
});
watcher.on('event', ({ result }) => {
if (result) {
result.close();
Expand Down
61 changes: 61 additions & 0 deletions build/plugins/dev-server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Router from '@koa/router';
import Koa from 'koa';
import fs from 'node:fs/promises';
import path from 'node:path';
import { PassThrough } from 'node:stream';

/** @returns {import("rollup").Plugin} */
const devServer = ({ port = 3000 } = {}) => {
const koa = new Koa();
const router = new Router();

let sendCommand = null;
router.get('/__dev_server', (ctx) => {
ctx.set('Content-Type', 'text/event-stream');
ctx.set('Cache-Control', 'no-cache');
ctx.set('Connection', 'keep-alive');
const stream = new PassThrough();
ctx.status = 200;
ctx.body = stream;
sendCommand = (cmd) => {
stream.write(`data: ${cmd}\n\n`);
};
ctx.req.on('close', () => {
sendCommand = null;
});
});

let html = '';
router.get('/', (ctx) => {
ctx.body = html;
});

koa.use(router.routes()).use(router.allowedMethods());
koa.listen(port, '0.0.0.0');

return {
name: 'dev-server',
watchChange() {
sendCommand?.('update');
},
async generateBundle(_, bundle) {
let body = '';
Object.values(bundle).forEach((file) => {
if (
path.extname(file.fileName) === '.html' &&
!file.fileName.endsWith('back.html')
) {
body += file.source;
}
});
body += `<script> ${await fs.readFile(path.resolve(import.meta.dirname, 'runtime.js'), { encoding: 'utf-8' })} </script>`;
html = `<!DOCTYPE html>
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
<body>${body}</body>
`;
sendCommand?.('refresh');
},
};
};

export default devServer;
12 changes: 12 additions & 0 deletions build/plugins/dev-server/runtime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const source = new EventSource('/__dev_server');

source.onmessage = (event) => {
switch (event.data) {
case 'refresh':
location.reload();
break;
case 'update':
console.log('code updated. Will refresh after build.');
break;
}
};
22 changes: 22 additions & 0 deletions build/plugins/generate-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { extname } from 'node:path';

export default () => ({
name: 'generate-template',
generateBundle(_, bundle) {
Object.keys(bundle)
.filter((fileName) => extname(fileName) !== '.html')
.forEach((fileName) => {
delete bundle[fileName];
});
this.emitFile({
type: 'asset',
fileName: `style.css`,
source: ``,
});
this.emitFile({
type: 'asset',
fileName: `back.html`,
source: `<div id="at-back-indicator"></div>{{FrontSide}}`,
});
},
});
62 changes: 23 additions & 39 deletions build/rollup.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import devServer from './plugins/dev-server/index.js';
import generateTemplate from './plugins/generate-template.js';
import { readJson, ensureValue } from './utils.js';
import alias from '@rollup/plugin-alias';
import commonjs from '@rollup/plugin-commonjs';
Expand All @@ -12,7 +14,7 @@ import { dataToEsm } from '@rollup/pluginutils';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import fs from 'node:fs/promises';
import { extname, resolve } from 'node:path';
import { resolve } from 'node:path';
import postcss from 'rollup-plugin-postcss';
import { swc } from 'rollup-plugin-swc3';
import { visualizer } from 'rollup-plugin-visualizer';
Expand Down Expand Up @@ -109,6 +111,26 @@ export async function rollupOptions(config) {
}),
url(),
visualizer(),
html({
fileName: `front.html`,
template({ files }) {
let frontHtml = '';
frontHtml += `<div data-at-version="${packageJson.version}" id="at-root"></div>`;
frontHtml += `<style>${files?.css?.map(({ source }) => source).join('')}</style>`;
frontHtml += `
<div id="at-fields" style="display:none;">
${buildFields()}
</div>
`;
frontHtml +=
files.js
?.map(({ code }) => `<script>${code}</script>`)
.join('') || '';
return frontHtml;
},
}),
generateTemplate(),
envValue(false, () => devServer()),
],
onwarn(warning, warn) {
if (warning.code === 'MODULE_LEVEL_DIRECTIVE') {
Expand All @@ -133,44 +155,6 @@ export async function rollupOptions(config) {
}),
false,
),
html({
fileName: `front.html`,
template({ files }) {
let frontHtml = '';
frontHtml += `<div data-at-version="${packageJson.version}" id="at-root"></div>`;
frontHtml += `<style>${files?.css?.map(({ source }) => source).join('')}</style>`;
frontHtml += `
<div id="at-fields" style="display:none;">
${buildFields()}
</div>
`;
frontHtml +=
files.js
?.map(({ code }) => `<script>${code}</script>`)
.join('') || '';
return frontHtml;
},
}),
{
name: 'generate-template',
generateBundle(_, bundle) {
Object.keys(bundle)
.filter((fileName) => extname(fileName) !== '.html')
.forEach((fileName) => {
delete bundle[fileName];
});
this.emitFile({
type: 'asset',
fileName: `style.css`,
source: ``,
});
this.emitFile({
type: 'asset',
fileName: `back.html`,
source: `<div id="at-back-indicator"></div>{{FrontSide}}`,
});
},
},
],
};
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"devDependencies": {
"@changesets/cli": "^2.27.10",
"@eslint/js": "^9.9.1",
"@koa/router": "^13.1.0",
"@rollup/plugin-alias": "^5.1.0",
"@rollup/plugin-commonjs": "^26.0.1",
"@rollup/plugin-html": "^1.0.3",
Expand Down
36 changes: 36 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 6ad518b

Please sign in to comment.