@zubra/server 5.7.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zubra/server",
3
- "version": "5.7.0",
3
+ "version": "5.8.0",
4
4
  "description": "Zubra on the server: render components into any template engine's pages, serve their browser modules, and give frameworks' HTML its components' shadow roots.",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -35,8 +35,8 @@
35
35
  "test": "node --test \"test/*.test.js\""
36
36
  },
37
37
  "peerDependencies": {
38
- "@zubra/compiler": "^5.7.0",
39
- "@zubra/runtime": "^5.7.0"
38
+ "@zubra/compiler": "^5.8.0",
39
+ "@zubra/runtime": "^5.8.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@minify-html/node": "0.18.1",
package/src/core.js CHANGED
@@ -19,7 +19,8 @@ export { SOURCE_EXTENSION, TYPES };
19
19
  * host serves under `<base>/` beyond the components' modules (`{ status, type, body }` or null).
20
20
  * `needs(name, code)`: the host's check on a compiled module (a package it needs being installed).
21
21
  */
22
- export function createCore({ request, files, sourcesOf: readSources, cache = true, devtools = false, base, imports = {}, syncImports = {}, needs = (_name, code) => code, where = 'the components', assets = () => null, warn = (message) => console.warn(message) }) {
22
+ export function createCore({ request, files, sourcesOf: readSources, cache = true, devtools = false, base, imports = {}, syncImports = {}, needs = (_name, code) => code, where = 'the components', assets = () => null, warn = (message) => console.warn(message), clientModules = 'all' }) {
23
+ if (clientModules !== 'all' && clientModules !== 'needed') throw new Error(`@zubra/server: clientModules is "all" or "needed", not ${JSON.stringify(clientModules)}`);
23
24
  const memo = new Map();
24
25
  const once = (key, make) => {
25
26
  if (!cache || !memo.has(key)) memo.set(key, make());
@@ -67,7 +68,15 @@ export function createCore({ request, files, sourcesOf: readSources, cache = tru
67
68
  const styles = names.map(css).join('\n');
68
69
  return `${styles ? `<style data-zb-components>${styles}</style>\n` : ''}${importMap()}`;
69
70
  };
70
- const scripts = (names, async = false) => (names.length ? `<script type="module"${async ? ' async' : ''}>${names.map((name) => `import '${base}/components/${name}.js';`).join(' ')}</script>` : '');
71
+ // `clientModules: 'needed'`: a component whose server HTML is complete on its own (the
72
+ // compiler's `client` list is empty: no state, handlers, hooks or values computed in the
73
+ // browser, in it or the components it uses) gets no module. For pages that never change
74
+ // those components' props from script.
75
+ const shipped = (names) => (clientModules === 'needed' ? names.filter((name) => (describe(name).client ?? ['unknown']).length > 0) : names);
76
+ const scripts = (all, async = false) => {
77
+ const names = shipped(all);
78
+ return names.length ? `<script type="module"${async ? ' async' : ''}>${names.map((name) => `import '${base}/components/${name}.js';`).join(' ')}</script>` : '';
79
+ };
71
80
 
72
81
  /** What a request for `pathname` gets: `{ status, type, body }`, or null if it isn't ours. */
73
82
  function serve(pathname) {
package/src/edge.js CHANGED
@@ -37,7 +37,7 @@ function normalize(path) {
37
37
  * `cache`, `devtools` (off by default here: the DevTools need the runtime's development build,
38
38
  * which you would have to serve yourself) and `imports`.
39
39
  */
40
- export function createZubra({ wasm, compiler = wasm ? createCompiler(wasm) : null, components = {}, prefix = '/_zubra', cache = true, devtools = false, imports = {}, warn } = {}) {
40
+ export function createZubra({ wasm, compiler = wasm ? createCompiler(wasm) : null, components = {}, prefix = '/_zubra', cache = true, devtools = false, imports = {}, warn, clientModules } = {}) {
41
41
  if (!compiler) throw new Error("@zubra/server/edge: createZubra() needs the compiler's WebAssembly module (`wasm`), or a `compiler` from createCompiler()");
42
42
  const sources = new Map(); // path → source
43
43
  const files = new Map(); // name → path
@@ -74,6 +74,7 @@ export function createZubra({ wasm, compiler = wasm ? createCompiler(wasm) : nul
74
74
 
75
75
  return createCore({
76
76
  warn,
77
+ clientModules,
77
78
  request: (body) => compiler.request(body),
78
79
  files,
79
80
  sourcesOf: (path) => sourcesOf(path),
package/src/index.js CHANGED
@@ -43,7 +43,7 @@ const posix = (path) => path.split(sep).join('/');
43
43
  *
44
44
  * Everything that doesn't need a disk is in `core.js`, shared with `edge.js` (Workers).
45
45
  */
46
- export function createZubra({ components = 'components', prefix = '/_zubra', cache = true, production = process.env.NODE_ENV === 'production', devtools = process.env.ZUBRA_DEVTOOLS === '1' || !production, imports = {}, warn } = {}) {
46
+ export function createZubra({ components = 'components', prefix = '/_zubra', cache = true, production = process.env.NODE_ENV === 'production', devtools = process.env.ZUBRA_DEVTOOLS === '1' || !production, imports = {}, warn, clientModules } = {}) {
47
47
  const root = resolve(components);
48
48
  if (!existsSync(root)) throw new Error(`@zubra/server: no components folder at ${root}`);
49
49
  const sourceDir = dirname(fileURLToPath(import.meta.resolve('@zubra/runtime')));
@@ -100,6 +100,7 @@ export function createZubra({ components = 'components', prefix = '/_zubra', cac
100
100
 
101
101
  const core = createCore({
102
102
  warn,
103
+ clientModules,
103
104
  request: (body) => compiler.request(body),
104
105
  files,
105
106
  sourcesOf: (path) => compiler.sources(path),