console.log(e)} />
26 | `;
27 | }
28 |
29 | // Binds the event on div using `addEventListener`.
30 | innerHTML(document.body, render());
31 | ```
32 |
33 | A good use case for this middleware is building a Chrome Extension where using
34 | inline event handlers is not possible. Supports non-bubbling events via the
35 | `useCapture` flag.
36 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-synthetic-events/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './dist/es/index.js';
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-synthetic-events/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffhtml-middleware-synthetic-events",
3 | "version": "1.0.0-beta.30",
4 | "description": "Global event delegation middleware, avoids inline events",
5 | "type": "module",
6 | "main": "dist/cjs/index",
7 | "module": "dist/es/index",
8 | "scripts": {
9 | "prepublishOnly": "npm run build",
10 | "clean": "rm -rf dist/* && mkdir -p dist",
11 | "build": "npm run clean && npm run build-umd && npm run build-cjs && npm run build-esm && npm run build-min",
12 | "build-cjs": "NODE_ENV=cjs babel lib -d dist/cjs && sh ../../post-cjs.sh",
13 | "build-esm": "NODE_ENV=esm babel lib -d dist/es",
14 | "build-umd": "NODE_ENV=umd rollup -c rollup.config.js",
15 | "build-min": "NODE_ENV=min rollup -c rollup.config.js && uglifyjs dist/synthetic-events.min.js -o dist/synthetic-events.min.js -m -c",
16 | "watch": "NODE_ENV=umd rollup -c rollup.config.js -w"
17 | },
18 | "keywords": [
19 | "diffhtml",
20 | "middleware",
21 | "synthetic",
22 | "events"
23 | ],
24 | "author": "Tim Branyen (@tbranyen)",
25 | "license": "MIT",
26 | "devDependencies": {
27 | "@babel/cli": "^7.12.10",
28 | "@babel/core": "^7.12.10",
29 | "babel-preset-diffhtml-imports": "^1.0.0-beta.30",
30 | "diffhtml": "^1.0.0-beta.30",
31 | "rollup": "^1.21.4",
32 | "rollup-plugin-babel": "^4.3.3",
33 | "rollup-plugin-node-resolve": "^5.2.0",
34 | "rollup-plugin-replace": "^2.2.0",
35 | "rollup-plugin-visualizer": "^2.6.0",
36 | "rollup-watch": "^4.3.1",
37 | "uglify-js": "^3.12.4"
38 | },
39 | "gitHead": "091b497588f6f48221630431e2f1eeb7f2db37cb"
40 | }
41 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-synthetic-events/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import nodeResolve from 'rollup-plugin-node-resolve';
3 | import replace from 'rollup-plugin-replace';
4 | import Visualizer from 'rollup-plugin-visualizer';
5 |
6 | const entries = {
7 | min: 'lib/index.js',
8 | umd: 'lib/index.js',
9 | };
10 |
11 | const dests = {
12 | min: 'dist/synthetic-events.min.js',
13 | umd: 'dist/synthetic-events.js',
14 | }
15 |
16 | const { NODE_ENV = 'umd' } = process.env;
17 |
18 | export const input = entries[NODE_ENV];
19 | export const context = 'this';
20 | export const external = ['diffhtml'];
21 |
22 | export const output = [{
23 | file: dests[NODE_ENV],
24 | format: 'umd',
25 | exports: 'default',
26 | name: 'syntheticEvents',
27 | sourcemap: false,
28 | globals: { diffhtml: 'diff' },
29 | }];
30 |
31 | export const plugins = [
32 | NODE_ENV === 'min' && replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
33 | babel(),
34 | nodeResolve({ mainFields: ['module'] }),
35 | NODE_ENV === 'umd' && Visualizer({ filename: './dist/build-size.html' }),
36 | ];
37 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["diffhtml-imports"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/README.md:
--------------------------------------------------------------------------------
1 | # <±/> diffHTML Verify State Middleware
2 |
3 | Stable Version: 1.0.0-beta.30
4 |
5 | Asserts that a render properly updated the old Virtual Tree and the DOM. Will
6 | recursively search for inconsistencies, displays warnings unless debugging is
7 | enabled, then it throws errors instead.
8 |
9 | 
10 |
11 | ##### Installation
12 |
13 | ``` sh
14 | npm install diffhtml-middleware-verify-state
15 | ```
16 |
17 | ##### Example
18 |
19 | ``` javascript
20 | import { use } from 'diffhtml';
21 | import verifyState from 'diffhtml-middleware-verify-state';
22 |
23 | // Throw when debug is truthy (when location.search has `?debug`)
24 | use(verifyState({ debug: location.search.includes('debug') }));
25 | ```
26 |
27 | This is not a very performant middleware, so please do not use this in
28 | production where performance is critical. Use in development.
29 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './dist/es/index.js';
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffhtml-middleware-verify-state",
3 | "version": "1.0.0-beta.30",
4 | "description": "Verifies render state middleware, useful for sanity checking",
5 | "type": "module",
6 | "main": "dist/cjs/index",
7 | "module": "dist/es/index",
8 | "scripts": {
9 | "prepublishOnly": "npm run build",
10 | "clean": "rm -rf dist/* && mkdir -p dist",
11 | "build": "npm run clean && npm run build-umd && npm run build-cjs && npm run build-esm && npm run build-min",
12 | "build-cjs": "NODE_ENV=cjs babel lib -d dist/cjs && sh ../../post-cjs.sh",
13 | "build-esm": "NODE_ENV=esm babel lib -d dist/es",
14 | "build-umd": "NODE_ENV=umd rollup -c rollup.config.js",
15 | "build-min": "NODE_ENV=min rollup -c rollup.config.js && uglifyjs dist/verify-state.min.js -o dist/verify-state.min.js -m -c",
16 | "watch": "NODE_ENV=umd rollup -c rollup.config.js -w"
17 | },
18 | "keywords": [
19 | "diffhtml",
20 | "middleware",
21 | "verify state"
22 | ],
23 | "author": "Tim Branyen",
24 | "license": "MIT",
25 | "devDependencies": {
26 | "@babel/cli": "^7.12.10",
27 | "@babel/core": "^7.12.10",
28 | "babel-preset-diffhtml-imports": "^1.0.0-beta.30",
29 | "diffhtml": "^1.0.0-beta.30",
30 | "rollup": "^1.21.4",
31 | "rollup-plugin-babel": "^4.3.3",
32 | "rollup-plugin-hypothetical": "^2.1.0",
33 | "rollup-plugin-node-resolve": "^5.2.0",
34 | "rollup-plugin-replace": "^2.2.0",
35 | "rollup-plugin-visualizer": "^2.6.0",
36 | "rollup-watch": "^4.3.1",
37 | "uglify-js": "^3.12.4"
38 | },
39 | "gitHead": "091b497588f6f48221630431e2f1eeb7f2db37cb"
40 | }
41 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-verify-state/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import nodeResolve from 'rollup-plugin-node-resolve';
3 | import replace from 'rollup-plugin-replace';
4 | import Visualizer from 'rollup-plugin-visualizer';
5 |
6 | const entries = {
7 | min: 'lib/index.js',
8 | umd: 'lib/index.js',
9 | };
10 |
11 | const dests = {
12 | min: 'dist/verify-state.min.js',
13 | umd: 'dist/verify-state.js',
14 | }
15 |
16 | const { NODE_ENV = 'umd' } = process.env;
17 |
18 | export const input = entries[NODE_ENV];
19 | export const context = 'this';
20 | export const external = ['diffhtml'];
21 |
22 | export const output = [{
23 | file: dests[NODE_ENV],
24 | format: 'umd',
25 | exports: 'default',
26 | name: 'verifyState',
27 | sourcemap: false,
28 | globals: { diffhtml: 'diff' },
29 | }];
30 |
31 | export const plugins = [
32 | replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
33 | babel(),
34 | nodeResolve({ mainFields: ['module'] }),
35 | NODE_ENV === 'umd' && Visualizer({ filename: './dist/build-size.html' }),
36 | ];
37 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["diffhtml-imports"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/README.md:
--------------------------------------------------------------------------------
1 | # <±/> diffHTML Worker Middleware
2 |
3 | Stable Version: 1.0.0-beta.23
4 |
5 | Used to separate the diffing and patching stages of rendering across threads.
6 | The main thread receives payloads containing mutations to apply, all UI logic
7 | is isolated within a worker thread.
8 |
9 | Can be used with Node.js servers and pass patches to the client using Web
10 | Sockets.
11 |
12 | ## Installation
13 |
14 | ``` sh
15 | npm install diffhtml-middleware-worker
16 | ```
17 |
18 | ## Usage
19 |
20 | When you create a worker, you bind it to a mount point and all `innerHTML` or
21 | `outerHTML` calls that get made in the worker are intercepted and passed to the
22 | main thread.
23 |
24 | ### In a browser
25 |
26 | To create a web worker in the browser, import the `createWebWorker` function.
27 | Invoke this with a file path pointing to the location of your module that
28 | contains the rendering logic. This file path will be explained more after the
29 | following code snippet.
30 |
31 | You must import either the core or lite version in the main thread to do the
32 | actual patching. The lite version is preferable due to the smaller filesize.
33 | Then register the middleware into the main thread.
34 |
35 | ```js
36 | import { use } from 'https://diffhtml.org/core/lite';
37 | import { mainTask, createWebWorker } from 'https://diffhtml.org/middleware-worker';
38 |
39 | use(mainTask());
40 | ```
41 |
42 | Once the middleware is registered, you can create web workers using the helper
43 | function. If you already have a worker you can pass it instead of a string to
44 | have the events hooked up.
45 |
46 | ```js
47 | const mount = document.body;
48 | createWebWorker('./path/to/worker.js', { mount });
49 | ```
50 |
51 | The above code will create a worker that exists at `worker.js` and proxy all
52 | rendering from it into the mount point, in this case the `` tag. You
53 | must register the `workerTask` middleware inside the worker to ensure patches
54 | are properly passed to the main thread.
55 |
56 | ```js
57 | import { use, html, createTree, innerHTML } from 'https://diffhtml.org/core';
58 | import { workerTask } from 'https://diffhtml.org/middleware-worker';
59 |
60 | use(workerTask());
61 | ```
62 |
63 | In the worker you must create a placeholder to render into. This will
64 | emulate the mount in the main thread.
65 |
66 | ```js
67 | // Create an empty fragment to render into, this represents the body tag
68 | // in the main thread.
69 | const placeholder = createTree();
70 |
71 | // Any outerHTML or innerHTML calls will be proxied to the main thread mount
72 | // point.
73 | innerHTML(placeholder, html`
74 |
Hello world from a worker thread!
75 | `);
76 | ```
77 |
78 | ### With Node.js
79 |
80 |
81 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/index.js:
--------------------------------------------------------------------------------
1 | export * from './dist/es/index.js';
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "module": "esnext",
5 | "target": "es2017",
6 | "declaration": true,
7 | "checkJs": true,
8 | "noUnusedParameters": true,
9 | "noUnusedLocals": true,
10 | "outDir": "./dist/typings",
11 | "lib": ["es2017", "dom"]
12 | },
13 | "include": ["lib/**/*"]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/create-web-socket.js:
--------------------------------------------------------------------------------
1 | import diff from './util/binding';
2 |
3 | const { innerHTML, html } = diff;
4 | const { parse } = JSON;
5 |
6 | export const createWebSocket = (socketUrl, { mount, socketOptions }) => {
7 | const socket = new WebSocket(socketUrl, socketOptions);
8 |
9 | socket.addEventListener('message', async e => {
10 | const { type, ...rest } = parse(e.data);
11 |
12 | // TODO Deprecate the 'clear' event. This is currently used in the Node
13 | // worker when an error is encountered. This cleans up the markup to avoid
14 | // issues during rendering.
15 | if (type === 'clear') {
16 | mount.innerHTML = '';
17 | }
18 |
19 | if (type === 'patches') {
20 | innerHTML(mount, null, { patches: rest.patches });
21 | }
22 |
23 | if (type === 'log') {
24 | const { level, message } = rest;
25 | console[level](...[].concat(message));
26 | }
27 | });
28 |
29 | return socket;
30 | };
31 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/create-worker.js:
--------------------------------------------------------------------------------
1 | import { type } from './util/types';
2 | import NodeWorker from './util/node-worker-threads';
3 |
4 | const isNode = typeof global !== 'undefined';
5 | const SafeWorker = typeof Worker !== 'undefined' ? Worker : NodeWorker;
6 | const { stringify } = JSON;
7 |
8 | /**
9 | *
10 | * @param {string} workerInit - Location of worker script, Object URL pointing
11 | * to Blob, or a Worker instance itself.
12 | * @param {Object} workerOpts
13 | * @returns {Worker}
14 | */
15 | export const createWorker = (workerInit, workerOpts = {}) => callback => {
16 | const safeWorkerOpts = workerOpts || {};
17 |
18 | let worker = null;
19 |
20 | // If the init is a worker object already, simply assign the value and
21 | // options.
22 | if (type(workerInit) === 'worker') {
23 | worker = workerInit;
24 | Object.assign(worker, safeWorkerOpts);
25 | }
26 | // Otherwise, use the workerInit as the value for creating a new worker.
27 | else {
28 | worker = new SafeWorker(workerInit, { ...safeWorkerOpts });
29 | }
30 |
31 | const onMessage = message => {
32 | const { type, ...rest } = isNode ? message : message.data;
33 |
34 | if (type === 'patches') {
35 | callback({ type, ...rest });
36 | }
37 | };
38 |
39 | const onError = (error) => {
40 | // Extra logging to the Node console, in the browser the error will bubble
41 | // automatically so this isn't needed.
42 | if (isNode) {
43 | console.error(error);
44 | }
45 |
46 | callback({
47 | type: 'log',
48 | level: 'error',
49 | message: String(error.stack || error.message),
50 | });
51 |
52 | return true;
53 | };
54 |
55 | if (isNode) {
56 | worker.on('message', onMessage);
57 | worker.on('error', onError);
58 | }
59 | else {
60 | worker.onmessage = onMessage;
61 | worker.onerror = onError;
62 | }
63 |
64 | return worker;
65 | };
66 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/get-uuid.js:
--------------------------------------------------------------------------------
1 | import globalThis from './util/global';
2 | import nodeBuffer from './util/node-buffer';
3 |
4 | let Blob = globalThis.Blob;
5 |
6 | // First attempt to load using Node.js
7 | if (typeof Blob === 'undefined' && nodeBuffer) {
8 | Blob = nodeBuffer.Blob;
9 | }
10 |
11 | // If still not available, throw an error.
12 | if (typeof Blob === 'undefined') {
13 | throw new Error('Missing required Blob dependency');
14 | }
15 |
16 | // Extract UUID from object URL generated for an arbitrary blob.
17 | export const getUUID = () => URL.createObjectURL(new Blob()).slice(31);
18 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/index.js:
--------------------------------------------------------------------------------
1 | export { getUUID } from './get-uuid';
2 | export { toObjectURL } from './to-object-url';
3 | export { createWebSocket } from './create-web-socket';
4 | export { createWorker } from './create-worker';
5 | export { mainTask } from './main-task';
6 | export { workerTask } from './worker-task';
7 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/main-task.js:
--------------------------------------------------------------------------------
1 | import diff from './util/binding';
2 |
3 | const { Internals } = diff;
4 |
5 | const { assign } = Object;
6 | const { stringify } = JSON;
7 | const linker = new Map();
8 |
9 | export const mainTask = ({
10 | // TODO Merge socket and worker args together into one named bridge
11 | // or something similar.
12 | //
13 | // WebSocket connection for the main thread.
14 | socket = null,
15 | worker = null,
16 | } = {}) => assign(function webWorkerTask(transaction) {
17 | const currentTasks = transaction.tasks;
18 | const indexOfSyncTrees = currentTasks.indexOf(Internals.tasks.syncTrees);
19 |
20 | // Only run this middleware when patches are present.
21 | if (!('patches' in transaction.config)) {
22 | return;
23 | }
24 |
25 | const link = vTree => {
26 | if (vTree && vTree.childNodes) {
27 | Internals.Pool.memory.protected.add(vTree);
28 | linker.set(vTree.__link, vTree);
29 | vTree.childNodes.forEach(x => link(x));
30 | }
31 | };
32 |
33 | // Replace syncTrees with injectPatches
34 | currentTasks.splice(indexOfSyncTrees, 1, function injectPatches() {
35 | transaction.patches = transaction.config.patches.map(x => {
36 | // Handle dom events, custom element properties, etc. Any time you need
37 | // a function, we proxy the call and the arguments.
38 | if (x && x.__caller) {
39 | return function(e) {
40 | // TODO handled by synthetic events middleware
41 | e.preventDefault();
42 | e.stopPropagation();
43 |
44 | if (socket) {
45 | socket.send(stringify({ type: 'event', ...x }));
46 | }
47 | else {
48 | worker.postMessage({ type: 'event', ...x });
49 | }
50 | };
51 | }
52 |
53 | if (!x || typeof x !== 'object' || !('__link' in x)) {
54 | return x;
55 | }
56 |
57 | let vTree = x;
58 |
59 | if (linker.has(x.__link)) {
60 | vTree = linker.get(x.__link);
61 | return vTree;
62 | }
63 | else if (x.__link === 'mount') {
64 | vTree = transaction.oldTree;
65 | }
66 | else {
67 | link(vTree);
68 | }
69 |
70 | if (((x && x.isSvg) || (vTree && vTree.isSvg)) && vTree) {
71 | transaction.state.svgElements.add(vTree);
72 | }
73 |
74 | return vTree;
75 | });
76 | });
77 | }, {
78 | releaseHook: vTree => {
79 | if (vTree && vTree.__link) {
80 | linker.delete(vTree.__link);
81 | }
82 | },
83 | });
84 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/to-object-url.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates a virtual URL that can be used to create a Worker. This is useful
3 | * for inlining a script to run, vs using a phsyical file. Since the operations
4 | * are repetitive we offer this feature as a helper function.
5 | *
6 | * @param {Function} fn - Wrapper function containing code to execute in a
7 | * worker
8 | * @returns {String} URL
9 | */
10 | export function toObjectURL(fn) {
11 | const fnString = String(fn);
12 | const firstBracket = fnString.indexOf('{') + 1;
13 | const lastBracket = fnString.lastIndexOf('}');
14 | const workerCode = String(fn).slice(firstBracket, lastBracket);
15 |
16 | return URL.createObjectURL(
17 | // Create a new blob and split the workerCode so it becomes an array with a
18 | // single entry.
19 | new Blob(workerCode.split()),
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/util/binding.js:
--------------------------------------------------------------------------------
1 | import globalThis from './global';
2 | import { DIFF_BINDING } from './types';
3 |
4 | /**
5 | * @returns {DIFF_BINDING}
6 | */
7 | export default /** @type {DIFF_BINDING} */ (
8 | /** @type {any} */ (globalThis)[Symbol.for('diffHTML')]
9 | );
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/util/global.js:
--------------------------------------------------------------------------------
1 | /** @type {any} */
2 | export default (
3 | typeof global === 'object'
4 | ? global
5 | : (typeof window === 'object' ? window : self) || {}
6 | );
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/util/node-buffer.js:
--------------------------------------------------------------------------------
1 | let nodeBuffer = null;
2 |
3 | try {
4 | nodeBuffer = (await import('buffer')).default;
5 | }
6 | catch {}
7 |
8 | export default nodeBuffer;
9 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/util/node-worker-threads.js:
--------------------------------------------------------------------------------
1 | let nodeWorkerThreads = null;
2 |
3 | try {
4 | nodeWorkerThreads = (await import('worker_threads')).default;
5 | }
6 | catch {}
7 |
8 | export default nodeWorkerThreads;
9 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/lib/util/types.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Finds a more specific type identifier.
3 | *
4 | * @param {any} x
5 | * @returns {string}
6 | */
7 | export const type = x => toString.call(x).split(' ')[1].slice(0, -1).toLowerCase();
8 |
9 | /**
10 | * @type {{ [type: string]: any }}
11 | */
12 | export const EMPTY = {
13 | OBJ: {},
14 | };
15 |
16 | /** @typedef {import('diffhtml/dist/typings/index')} DIFF_BINDING */
17 | export const DIFF_BINDING = EMPTY.OBJ;
18 |
19 | /** @typedef {import('diffhtml/dist/typings/util/types').Mount} Mount */
20 | export const Mount = EMPTY.OBJ;
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffhtml-middleware-worker",
3 | "version": "1.0.0-beta.30",
4 | "description": "Provides worker rendering for client and server",
5 | "main": "dist/cjs/index",
6 | "type": "module",
7 | "module": "dist/es/index",
8 | "scripts": {
9 | "prepublishOnly": "npm run build",
10 | "clean": "rm -rf dist/* && mkdir -p dist",
11 | "build": "npm run clean && npm run build-umd && npm run build-cjs && npm run build-esm && npm run build-min",
12 | "build-cjs": "NODE_ENV=cjs babel lib -d dist/cjs && sh ../../post-cjs.sh",
13 | "build-esm": "NODE_ENV=esm babel lib -d dist/es",
14 | "build-umd": "NODE_ENV=umd rollup -c rollup.config.js",
15 | "build-min": "NODE_ENV=min rollup -c rollup.config.js && uglifyjs dist/worker.min.js -o dist/worker.min.js -m -c",
16 | "watch": "NODE_ENV=umd rollup -c rollup.config.js -w"
17 | },
18 | "keywords": [
19 | "diffhtml",
20 | "worker",
21 | "middleware"
22 | ],
23 | "author": "Tim Branyen (@tbranyen)",
24 | "license": "MIT",
25 | "devDependencies": {
26 | "@babel/cli": "^7.12.10",
27 | "@babel/core": "^7.12.10",
28 | "babel-preset-diffhtml-imports": "^1.0.0-beta.30",
29 | "diffhtml": "^1.0.0-beta.30",
30 | "rollup": "^1.21.4",
31 | "rollup-plugin-babel": "^4.3.3",
32 | "rollup-plugin-hypothetical": "^2.1.0",
33 | "rollup-plugin-node-resolve": "^5.2.0",
34 | "rollup-plugin-replace": "^2.2.0",
35 | "rollup-plugin-visualizer": "^2.6.0",
36 | "rollup-watch": "^4.3.1",
37 | "uglify-js": "^3.12.4"
38 | },
39 | "gitHead": "091b497588f6f48221630431e2f1eeb7f2db37cb"
40 | }
41 |
--------------------------------------------------------------------------------
/packages/diffhtml-middleware-worker/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import nodeResolve from 'rollup-plugin-node-resolve';
3 | import replace from 'rollup-plugin-replace';
4 | import hypothetical from 'rollup-plugin-hypothetical';
5 | import Visualizer from 'rollup-plugin-visualizer';
6 |
7 | const entries = {
8 | min: 'lib/index.js',
9 | umd: 'lib/index.js',
10 | };
11 |
12 | const dests = {
13 | min: 'dist/worker.min.js',
14 | umd: 'dist/worker.js',
15 | }
16 |
17 | const { NODE_ENV = 'umd' } = process.env;
18 |
19 | export const input = entries[NODE_ENV];
20 | export const context = 'this';
21 | export const external = ['diffhtml'];
22 |
23 | export const output = [{
24 | file: dests[NODE_ENV],
25 | format: 'umd',
26 | exports: 'named',
27 | name: 'worker',
28 | sourcemap: false,
29 | globals: { diffhtml: 'diff' },
30 | }];
31 |
32 | const pluginDynamicImports = (options = {}) => ({
33 | name: 'dynamic-imports',
34 | transform(code, filename) {
35 | const transformedCode = code.replace(/import\(['"`](?![\.\/])(.*?)['"`]\)/gi, (match, request) => {
36 | return 'Promise.resolve(null)';
37 | if (request in options.globals) {
38 | return `Promise.resolve(global["${options.globals[request]}"])`;
39 | }
40 |
41 | return 'Promise.resolve(null)';
42 | });
43 |
44 | return transformedCode;
45 | },
46 | moduleParsed(moduleInfo) {
47 | console.log('here', moduleInfo);
48 | },
49 | });
50 |
51 | export const plugins = [
52 | pluginDynamicImports({
53 | globals: {
54 | 'fs': 'NodeFS',
55 | 'path': 'NodePath',
56 | 'worker_threads': 'NodeWorkerThreads',
57 | }
58 | }),
59 | NODE_ENV === 'min' && replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
60 | babel(),
61 | nodeResolve({
62 | preferBuiltins: true,
63 | mainFields: ['module'],
64 | }),
65 | hypothetical({
66 | allowFallthrough: true,
67 | files: {
68 | './lib/util/node-buffer.js': `
69 | export default undefined;
70 | `,
71 | './lib/util/node-worker-threads.js': `
72 | export default undefined;
73 | `,
74 | }
75 | }),
76 | NODE_ENV === 'umd' && Visualizer({ filename: './dist/build-size.html' }),
77 | ];
78 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["diffhtml-imports"]
3 | }
4 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/index.js:
--------------------------------------------------------------------------------
1 | export * from './dist/es/index.js';
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/lib/children.js:
--------------------------------------------------------------------------------
1 | export function map(children, fn, ctx) {
2 | if (children === undefined || children === null) {
3 | return null;
4 | }
5 |
6 | children = toArray(children);
7 |
8 | if (ctx && ctx !== children) {
9 | fn = fn.bind(ctx);
10 | }
11 |
12 | return children.map(fn);
13 | }
14 |
15 | export function forEach(children, fn, ctx) {
16 | if (children === undefined || children === null) {
17 | return null;
18 | }
19 |
20 | children = toArray(children);
21 |
22 | if (ctx && ctx !== children) {
23 | fn = fn.bind(ctx);
24 | }
25 |
26 | children.forEach(fn);
27 | }
28 |
29 | export function count(children) {
30 | return children ? children.length : 0;
31 | }
32 |
33 | export function only(children) {
34 | children = toArray(children).filter(({ nodeType }) => nodeType !== 3);
35 |
36 | return children.length ? children[0] : null;
37 | }
38 |
39 | export function toArray(children) {
40 | return Array.isArray(children) ? children : [].concat(children);
41 | }
42 |
43 | export default { map, forEach, count, only, toArray };
44 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/lib/fake-prop-types.js:
--------------------------------------------------------------------------------
1 | export default {};
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/lib/pure-component.js:
--------------------------------------------------------------------------------
1 | import { Component } from 'diffhtml-components';
2 |
3 | export default class PureComponent extends Component {
4 | shouldComponentUpdate(nextProps, nextState) {
5 | const nextPropKeys = keys(nextProps);
6 | const nextStateKeys = keys(nextState);
7 |
8 | if (nextPropKeys.length !== keys(this.props).length) {
9 | return true;
10 | }
11 | else if (nextStateKeys.length !== keys(this.state).length) {
12 | return true;
13 | }
14 |
15 | let isDirty = false;
16 |
17 | nextPropsKeys.forEach(keyName => {
18 | if (isDirty) { return; }
19 |
20 | if (this.props[keyName] !== nextProps[keyName]) {
21 | isDirty = true;
22 | }
23 | });
24 |
25 | if (isDirty) {
26 | return true;
27 | }
28 |
29 | nextStateKeys.forEach(keyName => {
30 | if (isDirty) { return; }
31 |
32 | if (this.state[keyName] !== nextState[keyName]) {
33 | isDirty = true;
34 | }
35 | });
36 |
37 | return isDirty;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffhtml-react-compat",
3 | "version": "1.0.0-beta.30",
4 | "description": "Provides a strong layer of compatibility with React",
5 | "type": "module",
6 | "main": "dist/react-compat.js",
7 | "module": "dist/es/index",
8 | "scripts": {
9 | "prepublishOnly": "npm run build",
10 | "clean": "rm -rf dist/* && mkdir -p dist",
11 | "build": "npm run clean && npm run build-umd && npm run build-cjs && npm run build-esm && npm run build-min",
12 | "build-cjs": "NODE_ENV=cjs babel lib -d dist/cjs && sh ../../post-cjs.sh",
13 | "build-esm": "NODE_ENV=esm babel lib -d dist/es",
14 | "build-umd": "NODE_ENV=umd rollup -c rollup.config.js",
15 | "build-min": "NODE_ENV=min rollup -c rollup.config.js && uglifyjs dist/react-compat.min.js -o dist/react-compat.min.js -m -c",
16 | "watch": "NODE_ENV=umd rollup -c rollup.config.js -w"
17 | },
18 | "author": "Tim Branyen (@tbranyen)",
19 | "license": "MIT",
20 | "devDependencies": {
21 | "@babel/cli": "^7.12.10",
22 | "@babel/core": "^7.12.10",
23 | "babel-preset-diffhtml-imports": "^1.0.0-beta.30",
24 | "diffhtml": "^1.0.0-beta.30",
25 | "prop-types": "^15.7.2",
26 | "rollup": "^1.21.4",
27 | "rollup-plugin-babel": "^4.3.3",
28 | "rollup-plugin-commonjs": "^10.1.0",
29 | "rollup-plugin-node-resolve": "^5.2.0",
30 | "rollup-plugin-replace": "^2.2.0",
31 | "rollup-plugin-visualizer": "^2.6.0",
32 | "rollup-watch": "^4.3.1",
33 | "uglify-js": "^3.12.4"
34 | },
35 | "dependencies": {
36 | "diffhtml-components": "^1.0.0-beta.30",
37 | "diffhtml-middleware-synthetic-events": "^1.0.0-beta.30",
38 | "prop-types": "^15.7.2"
39 | },
40 | "gitHead": "091b497588f6f48221630431e2f1eeb7f2db37cb"
41 | }
42 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import nodeResolve from 'rollup-plugin-node-resolve';
3 | import commonjs from 'rollup-plugin-commonjs';
4 | import replace from 'rollup-plugin-replace';
5 | import Visualizer from 'rollup-plugin-visualizer';
6 |
7 | const entries = {
8 | min: 'lib/index.js',
9 | umd: 'lib/index.js',
10 | };
11 |
12 | const dests = {
13 | min: 'dist/react-compat.min.js',
14 | umd: 'dist/react-compat.js',
15 | }
16 |
17 | const { NODE_ENV = 'umd' } = process.env;
18 |
19 | export const context = 'this';
20 | export const input = entries[NODE_ENV];
21 | export const external = ['diffhtml', 'prop-types'];
22 |
23 | export const output = {
24 | file: dests[NODE_ENV],
25 | format: 'umd',
26 | exports: 'named',
27 | globals: { diffhtml: 'diff', 'prop-types': 'PropTypes' },
28 | sourcemap: false,
29 | name: 'React',
30 | };
31 |
32 | export const plugins = [
33 | NODE_ENV === 'min' && replace({ 'process.env.NODE_ENV': JSON.stringify('production') }),
34 | babel({ runtimeHelpers: true }),
35 | (NODE_ENV !== 'umd' && NODE_ENV !== 'min') && nodeResolve({ jsnext: true, main: true, skip: external }),
36 | commonjs({ include: 'node_modules/**', }),
37 | NODE_ENV === 'umd' && Visualizer({ filename: './dist/build-size.html' }),
38 | ];
39 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/server.js:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-react-compat/test-utils.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tbranyen/diffhtml/f25d1c4acf8da35debb1e1f3f4af868f011ae0ab/packages/diffhtml-react-compat/test-utils.js
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/.cargo/config:
--------------------------------------------------------------------------------
1 | build = { target = "wasm32-unknown-unknown" }
2 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "diffhtml-rust-parser"
3 | version = "1.0.0-beta.29"
4 | edition = "2021"
5 |
6 | [lib]
7 | name = "parser"
8 | path = "src/parser.rs"
9 | test = false
10 | bench = false
11 | crate-type = ["cdylib"]
12 |
13 | [dependencies]
14 | tl = { version = "0.7.7", features = [] }
15 | wasm-bindgen = { version = "0.2.88", features = [] }
16 | serde = { version = "1.0", features = ["derive"] }
17 | js-sys = "0.3.60"
18 |
19 | [profile.release]
20 | strip = "symbols"
21 | lto = true
22 | opt-level = 3
23 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/Makefile:
--------------------------------------------------------------------------------
1 | default:
2 | cargo +nightly build --release
3 | mkdir -p dist
4 | wasm-bindgen ./target/wasm32-unknown-unknown/release/parser.wasm --target=bundler --omit-default-module-path --out-dir dist
5 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/README.md:
--------------------------------------------------------------------------------
1 | # Rust WASM HTML Parser
2 |
3 | Provides [tl a Rust-based zero-copy HTML parser](https://docs.rs/tl/latest/tl/)
4 | compiled to WASM, with a lightweight compatibility layer. This is an
5 | alternative to the regex-based parser found in the core source. You can use
6 | this alternative during a build, in the browser, and when writing server-side
7 | code.
8 |
9 | ## Build
10 |
11 | ```
12 | make
13 | ```
14 |
15 | ## Test
16 |
17 | ```
18 | npm t
19 | ```
20 |
21 | ## Using with diffHTML
22 |
23 | ```js
24 | import { Internals, innerHTML, html } from 'diffhtml';
25 | import { parse } from 'diffhtml-rust-parser';
26 |
27 | // Use the rust parser
28 | Internals.parse = parse;
29 |
30 | // Now the html`` tagged template will be parsed using WASM
31 | innerHTML(document.body, html`
32 |
Parsed with TL using WASM
33 | `);
34 |
35 | // Simple HTML strings are also automatically parsed using WASM now
36 | innerHTML(document.body, '
Also parsed with WASM
');
37 | ```
38 |
39 | ## Using with the Babel plugin
40 |
41 | To use the WASM plugin with you need to enable the Node WASM support as part of
42 | your build step. This is done with the `NODE_OPTIONS` env var and the
43 | `--experimental-wasm-modules` flag.
44 |
45 | ```json
46 | {
47 | "scripts": {
48 | "build": "NODE_OPTIONS=--experimental-wasm-modules babel input.js -o output.js"
49 | }
50 | }
51 | ```
52 |
53 | You need to use the JS version of the Babel config in order to pass the dynamic
54 | value. The JSON `.babelrc` is not compatible with the WASM parser.
55 |
56 | A `babel.config.js` config could look something like:
57 |
58 | ```js
59 | import { parse } from 'diffhtml-rust-parser';
60 |
61 | export default {
62 | plugins: [
63 | ['transform-diffhtml', {
64 | parse,
65 | }]
66 | ],
67 | };
68 | ```
69 |
70 | ## Using with Webpack
71 |
72 | This module is generated with bundlers and Node in mind. You should be able to
73 | consume it with a bundler that supports loading WASM like webpack. A sample
74 | example of how you could integrate the WASM parser in both development and
75 | production is available.
76 |
77 | - [Sample webpack example](./examples/webpack)
78 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/README.md:
--------------------------------------------------------------------------------
1 | # Webpack WASM Example
2 |
3 | This example demonstrates how to build the WASM parser into a web bundle using
4 | webpack.
5 |
6 | In development `npm run start` or `npm run build-dev`:
7 |
8 | - Build output is ~240KB
9 | - WASM is loaded asynchronously
10 | - Uses dev-server with `start`, outputs to the filesystem with `build-dev`
11 |
12 | In production `npm run build`:
13 |
14 | - Build output is ~20KB (7KB gzip)
15 | - Removes the parser resulting in a significantly smaller filesize
16 | - Uses Babel to pre-compile using the WASM parser to maintain consistency
17 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/babel.config.mjs:
--------------------------------------------------------------------------------
1 | import { parse } from 'diffhtml-rust-parser';
2 | import transformPlugin from 'babel-plugin-transform-diffhtml';
3 |
4 | export default {
5 | plugins: [
6 | [transformPlugin, { createTree: 'html', parse }]
7 | ],
8 | };
9 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Index
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/index.js:
--------------------------------------------------------------------------------
1 | import { Internals, innerHTML, html } from 'diffhtml';
2 | import { parse } from 'diffhtml-rust-parser';
3 |
4 | // Use Rust WASM parser at runtime during development
5 | Internals.parse = parse;
6 |
7 | function App() {
8 | return html`
9 |
console.log('clicked')}>
10 | This markup was parsed with WASM
11 |
12 | `;
13 | }
14 |
15 | innerHTML(document.body, App());
16 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack",
3 | "version": "1.0.0",
4 | "description": "Example of using WASM parser with webpack and babel",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "webpack serve",
8 | "build-dev": "webpack",
9 | "build": "NODE_OPTIONS=--experimental-wasm-modules NODE_ENV=production webpack -c webpack.config.prod.mjs"
10 | },
11 | "devDependencies": {
12 | "@babel/core": "^7.20.2",
13 | "@wasm-tool/wasm-pack-plugin": "^1.6.0",
14 | "babel-loader": "^9.1.0",
15 | "babel-plugin-transform-diffhtml": "file:../../../babel-plugin-transform-diffhtml",
16 | "diffhtml": "^1.0.0-beta.29",
17 | "diffhtml-rust-parser": "file:../../",
18 | "url-loader": "^4.1.1",
19 | "webpack": "^5.75.0",
20 | "webpack-cli": "^4.10.0",
21 | "webpack-dev-server": "^4.11.1",
22 | "webpack-virtual-modules": "^0.4.6"
23 | },
24 | "keywords": [],
25 | "author": "Tim Branyen (@tbranyen)",
26 | "license": "MIT"
27 | }
28 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/webpack.config.mjs:
--------------------------------------------------------------------------------
1 | import path from 'path';
2 | import { fileURLToPath } from 'url';
3 |
4 | const __dirname = path.dirname(fileURLToPath(import.meta.url));
5 | const dist = path.resolve(__dirname, 'dist');
6 |
7 | export default {
8 | mode: 'development',
9 | entry: {
10 | index: './index.js'
11 | },
12 | output: {
13 | path: dist,
14 | filename: 'build.js',
15 | publicPath: '/dist/',
16 | clean: true,
17 | },
18 | experiments: {
19 | futureDefaults: true,
20 | },
21 | devServer: {
22 | static: {
23 | directory: '.',
24 | }
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/examples/webpack/webpack.config.prod.mjs:
--------------------------------------------------------------------------------
1 | import webpack from 'webpack';
2 | import config from './webpack.config.mjs';
3 | import VirtualModulesPlugin from 'webpack-virtual-modules';
4 |
5 | const virtualModules = new VirtualModulesPlugin({
6 | './empty.js': `
7 | export const parse = () => {};
8 | `,
9 | });
10 |
11 | export default {
12 | ...config,
13 |
14 | mode: 'production',
15 |
16 | optimization: {
17 | minimize: true,
18 | },
19 |
20 | module: {
21 | rules: [
22 | {
23 | test: /\.js$/,
24 | exclude: /(node_modules)|(\.wasm$)/,
25 | use: {
26 | loader: 'babel-loader',
27 | }
28 | }
29 | ]
30 | },
31 |
32 | resolve: {
33 | alias: {
34 | 'diffhtml': 'diffhtml/dist/es/lite.js',
35 | 'diffhtml-rust-parser': './empty.js',
36 | },
37 | },
38 |
39 | plugins: [ virtualModules ],
40 | };
41 |
--------------------------------------------------------------------------------
/packages/diffhtml-rust-parser/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "diffhtml-rust-parser",
3 | "version": "1.0.0-beta.30",
4 | "description": "",
5 | "main": "dist/parser.js",
6 | "type": "module",
7 | "author": "Tim Branyen (@tbranyen)",
8 | "license": "MIT",
9 | "scripts": {
10 | "build": "make",
11 | "test": "node --experimental-wasm-modules test/index.js",
12 | "test-cov": "npm run test"
13 | },
14 | "devDependencies": {
15 | "diffhtml": "^1.0.0-beta.30"
16 | },
17 | "gitHead": "091b497588f6f48221630431e2f1eeb7f2db37cb"
18 | }
19 |
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "@babel/plugin-transform-modules-commonjs"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/README.md:
--------------------------------------------------------------------------------
1 | # <±/> diffHTML Static Sync
2 |
3 | *Static server that livereloads using VDOM on the entire page along with CSS.*
4 |
5 | Stable Version: 1.0.0-beta.30
6 |
7 | Provides a static HTTP server that monitors the folder it was executed in for
8 | changes. Whenever a file changes, it is read from disk and sent to the page
9 | using WebSockets. This server injects a client-side handler which responds to
10 | this WebSocket event, and using diffHTML, diffs the contents seamlessly without
11 | needing to reload. This includes all ``, ``, and `` tag
12 | changes. Provides smart CSS reloading, that instantly updates.
13 |
14 | Takes a "just works" approach by automatically injecting the synchronization
15 | code.
16 |
17 | ## Installation
18 |
19 | You can install via `yarn` or `npm`, below you will see commands to install
20 | globally which is what is most commonly used for command line tools.
21 |
22 | With npm:
23 |
24 | ``` sh
25 | npm install -g diffhtml-static-sync
26 | ```
27 |
28 | With yarn:
29 |
30 | ```
31 | yarn global add diffhtml-static-sync
32 | ```
33 |
34 | ## Usage
35 |
36 | If all goes well, you should now have a `diffhtml-static-sync` command in your
37 | `PATH` which means you can execute it in the command line. Open an existing
38 | folder with HTML files or make a new one and run this command in it. You
39 | shouldn't see any output just yet, but the command should appear to hang.
40 |
41 | Once you open your browser to: http://localhost:8000/ you should see the
42 | `index.html` file or a directory listing to chose from.
43 |
44 | Basic usage:
45 |
46 | ``` sh
47 | λ diffhtml-static-sync .
48 | Open http://localhost:8000
49 |
50 | Waiting for changes ⣻ Socket connection established
51 | ```
52 |
53 | Pass `--quiet` to prevent verbose logging in the browser console and terminal.
54 |
55 | ## Markdown
56 |
57 | Markdown is supported out-of-the-box, browse them as you would normal HTML
58 | files. Name your markdown files with `index.markdown` or `index.md` to be
59 | picked up automatically in folders.
60 |
61 | ## LiveReload
62 |
63 | By default any other file types are treated as a full page reload.
64 |
65 | ## Static Handler
66 |
67 | You can define your own handlers to respond to file changes. These are set up
68 | as a global `Set`. Like so:
69 |
70 | ``` js
71 | window.staticSyncHandlers = new Set();
72 | ```
73 |
74 | You can add your own function hooks into the Set, but calling `add`:
75 |
76 | ``` js
77 | staticSyncHandlers.add(({ file, markup /*, quiet */ }) => {
78 | if (file === 'some/file') {
79 | // Do something with the contents
80 | }
81 | });
82 | ```
83 |
84 | There is an optional argument quiet, shown above, that you can use to silence
85 | logging output to prevent clutter in the console. This is toggled from the
86 | `--quiet` CLI flag.
87 |
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | if (require.main === module) {
4 | return require('./lib/watch');
5 | }
6 |
7 | const { watch } = require('chokidar');
8 | const getSocket = require('./lib/socket');
9 |
10 | exports.clientScript = require('./lib/util/client-script');
11 |
12 | // Not an official API yet... only testing.
13 | exports.watch = (path, file, cb) => {
14 | const watcher = watch(path, { ignored: /[\/\\]\./, persistent: true, });
15 |
16 | getSocket.then(socket => {
17 | watcher.on('change', () => cb(markup => socket.send(
18 | JSON.stringify({
19 | file,
20 | markup,
21 | })
22 | )));
23 | });
24 | };
25 |
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/lib/socket.js:
--------------------------------------------------------------------------------
1 | const engine = require('engine.io');
2 | const server = engine.listen(process.env.WS_PORT || 54321);
3 |
4 | const sockets = new Set();
5 | const yellow = '\x1B[33m';
6 | const reset = '\x1B[m';
7 | const quiet = process.argv.includes('--quiet');
8 |
9 | module.exports = new Promise(resolve => {
10 | server.on('close', socket => sockets.delete(socket));
11 | server.on('error', socket => sockets.delete(socket));
12 |
13 | server.on('connection', socket => {
14 | socket.on('close', () => sockets.delete(socket));
15 |
16 | if (!quiet) {
17 | console.log(`${yellow}Socket connection established${reset}`);
18 | }
19 |
20 | // Broadcast client messages.
21 | socket.on('message', msg => {
22 | [...sockets].filter(x => socket !== x).forEach(socket => socket.send(msg));
23 | });
24 |
25 | sockets.add(socket);
26 | resolve(sockets);
27 | })
28 | });
29 |
30 | process.on('exit', () => server.close());
31 |
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/lib/util/client-script.js:
--------------------------------------------------------------------------------
1 | const { readFileSync } = require('fs');
2 | const { join } = require('path');
3 | const escape = require('./escape');
4 |
5 | module.exports = escape(readFileSync(join(__dirname, '../../dist/sync.js')));
--------------------------------------------------------------------------------
/packages/diffhtml-static-sync/lib/util/escape.js:
--------------------------------------------------------------------------------
1 | module.exports = script => {
2 | return String(script)
3 | .replace(/\