marko 5.21.2 → 5.21.3

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -39,7 +39,7 @@ number of times the button has been clicked.
39
39
  ```marko
40
40
  class {
41
41
  onCreate() {
42
- this.state = { count:0 };
42
+ this.state = { count: 0 };
43
43
  }
44
44
  increment() {
45
45
  this.state.count++;
@@ -48,12 +48,12 @@ class {
48
48
 
49
49
  style {
50
50
  .count {
51
- color:#09c;
52
- font-size:3em;
51
+ color: #09c;
52
+ font-size: 3em;
53
53
  }
54
54
  .example-button {
55
- font-size:1em;
56
- padding:0.5em;
55
+ font-size: 1em;
56
+ padding: 0.5em;
57
57
  }
58
58
  }
59
59
 
@@ -85,7 +85,7 @@ component style:
85
85
  **component.js**
86
86
 
87
87
  ```js
88
- module.exports = {
88
+ export default {
89
89
  onCreate() {
90
90
  this.state = { count: 0 };
91
91
  },
@@ -243,9 +243,8 @@ $ const searchResultsPromise = searchService.performSearch(keywords);
243
243
  Can’t decide if you want to do server-side rendering or client-side rendering?
244
244
  Why are we even talking about this in 2017? It doesn’t matter. Seriously, just
245
245
  do both. Marko makes this a no-brainer since you can render a Marko template
246
- directly to a stream (oh, and Marko will [automatically mount UI
247
- components](http://markojs.com/docs/server-side-rendering/) rendered on the
248
- server when the page loads in the browser):
246
+ directly to a stream (oh, and Marko will automatically mount UI
247
+ components rendered on the server when the page loads in the browser):
249
248
 
250
249
  ```js
251
250
  require("@marko/compiler/register"); // require .marko files!
@@ -289,4 +288,4 @@ Coming soon: auto correction and autonomous coding
289
288
 
290
289
  ---
291
290
 
292
- _Cover image credit:_ [Wikipedia](https://commons.wikimedia.org/wiki/File:Amanhecer_no_Hercules_--.jpg)
291
+ [_Cover image from Wikipedia_](https://commons.wikimedia.org/wiki/File:Amanhecer_no_Hercules_--.jpg)
@@ -28,7 +28,7 @@ Marko makes it easy to keep your component’s class and styles next to the HTML
28
28
 
29
29
  ## Server-side rendering
30
30
 
31
- A UI component can be rendered on the server or in the browser, but stateful component instances will be automatically mounted to the DOM in the browser for both. If a UI component tree is rendered on the server, then Marko will recreate the UI component tree in the browser with no extra code required. For more details, please see [Server-side rendering](/docs/server-side-rendering/).
31
+ A UI component can be rendered on the server or in the browser, but stateful component instances will be automatically mounted to the DOM in the browser for both. If a UI component tree is rendered on the server, then Marko will recreate the UI component tree in the browser with no extra code required. For more details, please see [Rendering](/docs/rendering/).
32
32
 
33
33
  ## Single-file components
34
34
 
@@ -107,7 +107,7 @@ counter/
107
107
  In your `component.js` file, export the component’s class:
108
108
 
109
109
  ```js
110
- module.exports = class {
110
+ export default class {
111
111
  onCreate() {
112
112
  this.state = {
113
113
  count: 0
@@ -116,7 +116,7 @@ module.exports = class {
116
116
  increment() {
117
117
  this.state.count++;
118
118
  }
119
- };
119
+ }
120
120
  ```
121
121
 
122
122
  In your `index.marko` file, you can reference methods from that class with `on-*` attributes:
@@ -141,7 +141,7 @@ And in your `style.css`, define the styles:
141
141
  If you target browsers that does not support classes, a plain object of methods can be exported:
142
142
 
143
143
  ```js
144
- module.exports = {
144
+ export default {
145
145
  onCreate: function () {
146
146
  this.state = {
147
147
  count: 0
@@ -214,7 +214,7 @@ class {
214
214
  `component-browser.js`
215
215
 
216
216
  ```js
217
- module.exports = {
217
+ export default {
218
218
  shout() {
219
219
  alert(`My favorite number is ${this.number}!`);
220
220
  }
@@ -5,21 +5,19 @@ project for a working example.
5
5
 
6
6
  ## Usage
7
7
 
8
- When using Marko with [Cloudflare Workers](https://workers.cloudflare.com/) you need to make sure that Marko is loaded with a `worker` [export condition](https://nodejs.org/api/packages.html#conditional-exports). Most bundlers support the ability to define export conditions.
8
+ When using Marko with [Cloudflare Workers](https://workers.cloudflare.com/), make sure that Marko is loaded with a `worker` [export condition](https://nodejs.org/api/packages.html#conditional-exports). Most bundlers support defining export conditions.
9
9
 
10
- After that point the `template.stream` will now return a worker compatible [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream).
11
-
12
- You can then simply respond with the returned stream.
10
+ After that point, imported `.marko` files will export a `.stream` method that returns a worker compatible [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream). You can then respond with that returned stream:
13
11
 
14
12
  ```js
15
- import template from "./index.marko";
13
+ import Template from "./index.marko";
16
14
 
17
15
  addEventListener("fetch", event => {
18
16
  event.respondWith(handleRequest(event.request));
19
17
  });
20
18
 
21
19
  async function handleRequest(request) {
22
- return new Response(template.stream(), {
20
+ return new Response(Template.stream(), {
23
21
  headers: {
24
22
  status: 200,
25
23
  headers: { "content-type": "text/html;charset=UTF-8" }
package/docs/compiler.md CHANGED
@@ -294,7 +294,7 @@ The hook will also receive a `types` object that matches the [@babel/types](http
294
294
  Here is an example hook:
295
295
 
296
296
  ```js
297
- module.exports = (tag, types) => {
297
+ export default (tag, types) => {
298
298
  if (types.isStringLiteral(tag.node.name)) {
299
299
  console.log(`Found a tag called ${tag.node.name.value}`);
300
300
  tag.remove();
package/docs/core-tags.md CHANGED
@@ -265,9 +265,17 @@ Optional attributes for `<await>`:
265
265
  | ---------------: | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
266
266
  | `timeout` | integer | An optional timeout. If reached, rejects the promise with a `TimeoutError`. |
267
267
  | `name` | string | Improves debugging and ensures ordering with the `show-after` attribute. |
268
- | `show-after` | string | Another `<await>` tag’s `name`. With `client-reorder`, ensures that the current `<await>` block will always show after the named `<await>`. |
268
+ | `show-after` | string | Another `<await>` tag’s `name`. Use with `client-reorder` to ensure that the current `<await>` will always render alongside or after the named `<await>`. |
269
269
  | `client-reorder` | boolean | If true, anything after this `<await>` will be server-rendered before the Promise completes, then the fulfilled Promise’s result will be updated with client-side JavaScript. |
270
270
 
271
+ Regardless of these attributes, the promise is executed as eagerly as possible. The attributes control how to coordinate rendering with the rest of the page:
272
+
273
+ - `client-reorder` prevents `<await>` blocks from delaying the HTTP stream, at the expense of making their rendering rely on client-side JS. Useful for making non-critical page sections not block HTML streaming of important content.
274
+
275
+ - Using `show-after` with `client-reorder` ensures that the current `<await>` block will always render simultaneously with or after the named `<await>`. Useful for cutting down on [layout shift](https://web.dev/debug-layout-shifts/). `<@placeholder>`s can help fine-tune the user experience while loading.
276
+
277
+ - `timeout` is useful for limiting non-critical content from slowing down the rest of the page too much.
278
+
271
279
  > **Pro Tip**: When using `timeout`, you can distinguish between `TimeoutError`s and promise rejections by checking the error’s `name`:
272
280
  >
273
281
  > ```marko
package/docs/express.md CHANGED
@@ -30,14 +30,14 @@ By using `res.marko` you'll automatically have access to `req`, `res`, `app`, `a
30
30
  ```javascript
31
31
  import express from "express";
32
32
  import markoPlugin from "@marko/express";
33
- import template from "./template.marko";
33
+ import Template from "./template.marko";
34
34
 
35
35
  const app = express();
36
36
 
37
37
  app.use(markoPlugin()); //enable res.marko(template, data)
38
38
 
39
39
  app.get("/", function (req, res) {
40
- res.marko(template, {
40
+ res.marko(Template, {
41
41
  name: "Frank",
42
42
  count: 30,
43
43
  colors: ["red", "green", "blue"]
package/docs/http.md CHANGED
@@ -7,13 +7,13 @@ project for a working example.
7
7
 
8
8
  ```js
9
9
  import http from "http";
10
- import template from "./index.marko";
10
+ import Template from "./index.marko";
11
11
 
12
12
  const port = 8080;
13
13
  const server = http.createServer();
14
14
 
15
15
  server.on("request", (req, res) => {
16
- template.render(
16
+ Template.render(
17
17
  {
18
18
  name: "Frank",
19
19
  count: 30,
package/docs/koa.md CHANGED
@@ -13,13 +13,13 @@ npm install koa marko --save
13
13
 
14
14
  ```javascript
15
15
  import Koa from "koa";
16
- import template from "./index.marko";
16
+ import Template from "./index.marko";
17
17
 
18
18
  const app = new Koa();
19
19
 
20
20
  app.use((ctx, next) => {
21
21
  ctx.type = "html";
22
- ctx.body = template.stream({
22
+ ctx.body = Template.stream({
23
23
  name: "Frank",
24
24
  count: 30,
25
25
  colors: ["red", "green", "blue"]
@@ -52,14 +52,13 @@ or
52
52
  yarn upgrade marko@^5
53
53
  ```
54
54
 
55
- > **Note**: Marko 5 has changed to using ES Modules. This means if you are using CJS modules to `require` a Marko template you will need to use the default property exported.
55
+ > **Note**: Marko 5 has changed to using ES Modules. This means if you are using CJS modules to `require` a Marko template you will need to use the `.default` property exported.
56
56
  >
57
57
  > ```js
58
58
  > const template = require("./template.marko");
59
- >
60
- > // Should become
59
+ > // …should become:
61
60
  > const template = require("./template.marko").default;
62
61
  >
63
- > // If you are already using es modules things remain the same
62
+ > // If already using ES Modules, things remain the same:
64
63
  > import template from "./template.marko";
65
64
  > ```
@@ -617,20 +617,20 @@ style.less {
617
617
 
618
618
  ### API
619
619
 
620
- Marko compiles component to JavaScript modules that export an API for rendering
621
- the component as shown below:
620
+ Marko compiles components to JavaScript modules that export their rendering APIs,
621
+ as shown below:
622
622
 
623
623
  ```js
624
- require("./components/greeting")
625
- .renderSync({ name: "Frank" })
626
- .appendTo(document.body);
624
+ import Greeting from "./components/greeting.marko";
625
+ Greeting.renderSync({ name: "Frank" }).appendTo(document.body);
627
626
  ```
628
627
 
629
- The same UI component can be rendered to a stream such as a writable HTTP
628
+ The same UI component can render to streams, such as a writable HTTP
630
629
  response stream:
631
630
 
632
631
  ```js
633
- require("./components/hello").render({ name: "John" }, res);
632
+ import Greeting from "./components/greeting.marko";
633
+ Greeting.render({ name: "John" }, res);
634
634
  ```
635
635
 
636
636
  > The users of a Marko UI component do not need to know that the component was
package/docs/redux.md CHANGED
@@ -17,7 +17,7 @@ The partial code below shows how a Marko UI component can connect to a Redux sto
17
17
  ### `counter.marko`
18
18
 
19
19
  ```marko
20
- import store from './store';
20
+ import store from './store.js';
21
21
 
22
22
  class {
23
23
  onMount () {
@@ -40,13 +40,13 @@ class {
40
40
  ### `reducer.js`
41
41
 
42
42
  ```js
43
- module.exports = function (state, action) {
43
+ export default function (state, action) {
44
44
  state = state || { value: 0 };
45
45
 
46
46
  // Additional reducer logic here…
47
47
 
48
48
  return state;
49
- };
49
+ }
50
50
  ```
51
51
 
52
52
  ### `store.js`
@@ -54,8 +54,8 @@ module.exports = function (state, action) {
54
54
  In `counter.marko`, the imported store module exports a Redux store created with the following code:
55
55
 
56
56
  ```js
57
- const redux = require("redux");
58
- const counter = require("./reducer");
57
+ import redux from "redux";
58
+ import counter from "./reducer.js";
59
59
 
60
- module.exports = redux.createStore(counter);
60
+ export default redux.createStore(counter);
61
61
  ```
package/docs/rendering.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Rendering
2
2
 
3
- To render a Marko view, you need to `require` it.
3
+ To render a Marko view, you need to `import` it.
4
4
 
5
5
  _example.js_
6
6
 
7
7
  ```js
8
- var fancyButton = require("./components/fancy-button");
8
+ import FancyButton from "./components/fancy-button.marko";
9
9
  ```
10
10
 
11
11
  > **Note:** If you are targeting node.js, you will need to enable the [require extension](./installing.md#require-marko-views) in order to require `.marko` files or you will need to precompile all of your templates using [Marko CLI](https://github.com/marko-js/cli). If you are targeting the browser, you will need to use a bundler like [`lasso`](./lasso.md), [`webpack`](./webpack.md) or [`rollup`](./rollup.md).
@@ -15,13 +15,13 @@ Once you have a view, you can pass input data and render it:
15
15
  _example.js_
16
16
 
17
17
  ```js
18
- var button = require("./components/fancy-button");
19
- var html = button.renderToString({ label: "Click me!" });
18
+ import FancyButton from "./components/fancy-button.marko";
19
+ const html = FancyButton.renderToString({ label: "Click me!" });
20
20
 
21
21
  console.log(html);
22
22
  ```
23
23
 
24
- The input data becomes available as `input` within a view, so if `fancy-button.marko` looked like this:
24
+ The data passed to `renderToString` becomes available as `input` in the component, so if `fancy-button.marko` looked like this:
25
25
 
26
26
  _./components/fancy-button.marko_
27
27
 
@@ -51,8 +51,8 @@ Many of these methods return a [`RenderResult`](#renderresult) which is an objec
51
51
  Using `renderSync` forces the render to complete synchronously. If a tag attempts to run asynchronously, an error will be thrown.
52
52
 
53
53
  ```js
54
- var view = require("./view"); // Import `./view.marko`
55
- var result = view.renderSync({});
54
+ import View from "./view.marko";
55
+ var result = View.renderSync({});
56
56
 
57
57
  result.appendTo(document.body);
58
58
  ```
@@ -67,8 +67,8 @@ result.appendTo(document.body);
67
67
  The `render` method returns an async `out` which is used to generate HTML on the server or a virtual DOM in the browser. In either case, the async `out` has a `then` method that follows the Promises/A+ spec, so it can be used as if it were a Promise. This promise resolves to a [`RenderResult`](#renderresult).
68
68
 
69
69
  ```js
70
- var view = require("./view"); // Import `./view.marko`
71
- var resultPromise = view.render({});
70
+ import View from "./view.marko";
71
+ var resultPromise = View.render({});
72
72
 
73
73
  resultPromise.then(result => {
74
74
  result.appendTo(document.body);
@@ -85,9 +85,9 @@ resultPromise.then(result => {
85
85
  | return value | `AsyncStream`/`AsyncVDOMBuilder` | the async `out` render target |
86
86
 
87
87
  ```js
88
- var view = require("./view"); // Import `./view.marko`
88
+ import View from "./view.marko";
89
89
 
90
- view.render({}, (err, result) => {
90
+ View.render({}, (err, result) => {
91
91
  result.appendTo(document.body);
92
92
  });
93
93
  ```
@@ -103,12 +103,12 @@ view.render({}, (err, result) => {
103
103
  The HTML output is written to the passed `stream`.
104
104
 
105
105
  ```js
106
- var http = require("http");
107
- var view = require("./view"); // Import `./view.marko`
106
+ import http from "http";
107
+ import View from "./view.marko";
108
108
 
109
109
  http.createServer((req, res) => {
110
110
  res.setHeader("content-type", "text/html");
111
- view.render({}, res);
111
+ View.render({}, res);
112
112
  });
113
113
  ```
114
114
 
@@ -123,10 +123,10 @@ http.createServer((req, res) => {
123
123
  The `render` method also allows passing an existing async `out`. If you do this, `render` will not automatically end the async `out` (this allows rendering a view in the middle of another view). If the async `out` won't be ended by other means, you are responsible for ending it.
124
124
 
125
125
  ```js
126
- var view = require("./view"); // Import `./view.marko`
127
- var out = view.createOut();
126
+ import View from "./view.marko";
127
+ var out = View.createOut();
128
128
 
129
- view.render({}, out);
129
+ View.render({}, out);
130
130
 
131
131
  out.on("finish", () => {
132
132
  console.log(out.getOutput());
@@ -145,8 +145,8 @@ out.end();
145
145
  Returns an HTML string and forces the render to complete synchronously. If a tag attempts to run asynchronously, an error will be thrown.
146
146
 
147
147
  ```js
148
- var view = require("./view"); // Import `./view.marko`
149
- var html = view.renderToString({});
148
+ import View from "./view.marko";
149
+ var html = View.renderToString({});
150
150
 
151
151
  document.body.innerHTML = html;
152
152
  ```
@@ -162,25 +162,27 @@ document.body.innerHTML = html;
162
162
  An HTML string is passed to the callback.
163
163
 
164
164
  ```js
165
- var view = require("./view"); // Import `./view.marko`
165
+ import View from "./view.marko";
166
166
 
167
- view.renderToString({}, (err, html) => {
167
+ View.renderToString({}, (err, html) => {
168
168
  document.body.innerHTML = html;
169
169
  });
170
170
  ```
171
171
 
172
172
  ### `stream(input)`
173
173
 
174
- The `stream` method returns a node.js style stream of the output HTML. This method is available on the server, but is not available by default in the browser. If you need to use streams in the browser, you may `require('marko/stream')` as part of your client-side bundle.
174
+ The `stream` method returns a Node.js-style stream of the output HTML.
175
175
 
176
176
  ```js
177
- var fs = require("fs");
178
- var view = require("./view"); // Import `./view.marko`
179
- var writeStream = fs.createWriteStream("output.html");
177
+ import fs from "fs";
178
+ import View from "./view.marko";
179
+ const writeStream = fs.createWriteStream("output.html");
180
180
 
181
- view.stream({}).pipe(writeStream);
181
+ View.stream({}).pipe(writeStream);
182
182
  ```
183
183
 
184
+ This method is available on the server, but not available by default in the browser. If you need to use streams in the browser, you may `import 'marko/stream'` as part of your client-side bundle.
185
+
184
186
  ## RenderResult
185
187
 
186
188
  ### `getComponent()`
@@ -207,35 +209,42 @@ view.stream({}).pipe(writeStream);
207
209
 
208
210
  ## Global data
209
211
 
210
- If you need to make data available globally to all views that are rendered as the result of a call to one of the above render methods, you can pass the data as a `$global` property on the input data object. This object will be removed from `input` and merged into the `out.global` property.
212
+ If you need to make data available to all rendered views, use the `$global` property on the input data object. This property will be removed from `input` and merged into the `out.global` property.
213
+
214
+ Global values persist across renders.
211
215
 
212
216
  ```js
213
- view.render({
217
+ View.render({
214
218
  $global: {
215
219
  flags: ["mobile"]
216
220
  }
217
221
  });
218
222
  ```
219
223
 
220
- To prevent sensitive data to be accidentally shipped to the browser, by default **none of the keys** in `out.global` is going to be sent to the browser. If you want the data to be serialized and ship to the frontend you need to specify it in `serializedGlobals` inside the `$global` object and they persist across re-renderings.
221
- The values need to be serializable.
224
+ > **Warning:** Use `$global` with caution; it is visible in any component.
225
+
226
+ ### Sending global data to browsers
227
+
228
+ ⚠️ To prevent accidentally exposing sensitive data, by default **no keys** in `out.global` are sent to browsers. To serialize data to the frontend, name the desired properties in `$global.serializedGlobals`.
229
+
230
+ Values must be serializable by [the `warp10` module](https://www.npmjs.com/package/warp10).
222
231
 
223
232
  ```js
233
+ import Page from "./index.marko";
234
+
224
235
  app.get("/", (req, res) => {
225
236
  const ua = req.get("User-Agent");
226
- const isIos = !!ua.match(/iPad|iPhone/);
227
- const isAndroid = !!ua.match(/Android/);
228
237
 
229
- require("./index.marko").render(
238
+ Page.render(
230
239
  {
231
240
  $global: {
232
- isIos, // isPad is serialized and available on the server and the browser in out.global.isPad
233
- isAndroid, // isAndroid is serialized and available on the server and the browser in out.global.isAndroid
234
- req, // req is going to be available only server side and will not be serialized because in not present in serializedGlobals below
241
+ isIos: /iPad|iPhone/.test(ua), // Serialized and available on the server and browser as `out.global.isIos`
242
+ isAndroid: /Android/.test(ua), // Serialized and available on the server and browser as `out.global.isAndroid`
243
+ req, // Only available server-side and not serialized, because it’s not in `serializedGlobals`
235
244
 
236
245
  serializedGlobals: {
237
- isIos: true, // Tell marko to serialize isIos above
238
- isAndroid: true // Tell marko to serialize isAndroid above
246
+ isIos: true, // Tell Marko to serialize `isIos`
247
+ isAndroid: true // Tell Marko to serialize `isAndroid`
239
248
  }
240
249
  }
241
250
  },
@@ -244,6 +253,4 @@ app.get("/", (req, res) => {
244
253
  });
245
254
  ```
246
255
 
247
- Use `$global` with judgement. It is global and visible in any component.
248
-
249
- Check [this PR](https://github.com/marko-js/marko/pull/672) for more details.
256
+ For details, check [#672: “Serialize only input and state on top-level server-rendered UI components”](https://github.com/marko-js/marko/pull/672).
@@ -35,7 +35,7 @@ Content Delivery Networks (CDNs) consider efficient streaming one of their best
35
35
 
36
36
  - Some [Akamai features designed to mitigate slow backends can ironically slow down fast chunked responses](https://community.akamai.com/customers/s/question/0D50f00006n975d/enabling-chunked-transfer-encoding-responses). Try toggling off Adaptive Acceleration, Ion, mPulse, Prefetch, and/or similar performance features. Also check for the following in the configuration:
37
37
 
38
- ```html
38
+ ```xml
39
39
  <network:http.buffer-response-v2>off</network:http.buffer-response-v2>
40
40
  ```
41
41
 
@@ -44,15 +44,15 @@ Content Delivery Networks (CDNs) consider efficient streaming one of their best
44
44
  For extreme cases where [Node streams very small HTML chunks with its built-in compression modules](https://github.com/marko-js/marko/pull/1641), you may need to tweak the compressor stream settings. Here’s an example with `createGzip` and its `Z_PARTIAL_FLUSH` flag:
45
45
 
46
46
  ```js
47
- const http = require("http");
48
- const zlib = require("zlib");
47
+ import http from "http";
48
+ import zlib from "zlib";
49
49
 
50
- const markoTemplate = require("./something.marko");
50
+ import MarkoTemplate from "./something.marko";
51
51
 
52
52
  http
53
53
  .createServer(function (request, response) {
54
54
  response.writeHead(200, { "content-type": "text/html;charset=utf-8" });
55
- const templateStream = markoTemplate.stream({});
55
+ const templateStream = MarkoTemplate.stream({});
56
56
  const gzipStream = zlib.createGzip({
57
57
  flush: zlib.constants.Z_PARTIAL_FLUSH
58
58
  });
package/docs/webpack.md CHANGED
@@ -116,21 +116,22 @@ export default {
116
116
  },
117
117
  ```
118
118
 
119
- ## Multiple client side compilers
119
+ ## Multiple client-side compilers
120
120
 
121
- Sometimes you need to have multiple compilers for your client side bundles. For example with [`i18n`](https://github.com/webpack/webpack/tree/master/examples/i18n) or [even shipping dynamic runtime bundles to the browser](https://github.com/eBay/arc/tree/master/packages/arc-webpack).
121
+ Sometimes you need multiple compilers for your client-side bundles. For example, with [`i18n`](https://github.com/webpack/webpack/tree/master/examples/i18n) or [even shipping dynamic runtime bundles to the browser](https://github.com/eBay/arc/tree/master/packages/arc-webpack).
122
122
 
123
- The Marko webpack browser plugin can be passed to multiple webpack compilers. At runtime you can provide a `$global.buildName` when rendering which will cause assets from the webpack compiler with that name to be included in the page.
123
+ The `@marko/webpack` plugin’s `.browser` property can be passed to multiple Webpack compilers. While rendering at runtime, you can provide a `$global.buildName` property to choose which assets from the Webpack compiler are included in the page.
124
124
 
125
- For example with the webpack i18n plugin you might have a config like the following:
125
+ For example, with the Webpack internationalization plugin, you might have a config like the following:
126
126
 
127
127
  ```js
128
128
  import MarkoPlugin from "@marko/webpack/plugin";
129
129
  import I18nPlugin from "i18n-webpack-plugin";
130
+ import germanTranslations from "./de.json";
130
131
 
131
132
  const languages = {
132
133
  en: null,
133
- de: require("./de.json")
134
+ de: germanTranslations
134
135
  };
135
136
 
136
137
  const markoPlugin = new MarkoPlugin();
@@ -167,20 +168,19 @@ export default [
167
168
  ];
168
169
  ```
169
170
 
170
- With the above config you can render your top level Marko template server side with a `$global.buildName`, like so:
171
+ With the above config, you can render your top-level Marko template server-side with a `$global.buildName` like so:
171
172
 
172
173
  ```javascript
173
174
  template.render({ $global: { buildName: "Browser-de" } });
174
175
  ```
175
176
 
176
- This will automatically send assets for the German language.
177
- Of course in this case you'll want to conditionally send the appropriate assets given a users locale. This can be some simply, like so:
177
+ That will automatically send German assets. However, what you _probably_ want instead of always serving German is conditionally sending appropriate assets for a user’s locale. This can be done like so:
178
178
 
179
179
  ```javascript
180
180
  template.render({ $global: { buildName: `Browser-${req.language}` } });
181
181
  ```
182
182
 
183
- Note: If a bundle with the provided name does not exist an error will be thrown.
183
+ **Note:** If a bundle with the provided `buildName` does not exist, an error is thrown.
184
184
 
185
185
  ## Multiple copies of Marko
186
186
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "5.21.2",
3
+ "version": "5.21.3",
4
4
  "license": "MIT",
5
5
  "description": "UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.",
6
6
  "dependencies": {
7
- "@marko/compiler": "^5.21.1",
8
- "@marko/translator-default": "^5.21.1",
7
+ "@marko/compiler": "^5.21.7",
8
+ "@marko/translator-default": "^5.21.3",
9
9
  "app-module-path": "^2.2.0",
10
10
  "argly": "^1.2.0",
11
11
  "browser-refresh-client": "1.1.4",
@@ -1,144 +0,0 @@
1
- # Server-side rendering
2
-
3
- Marko allows any Marko template/UI component to be rendered on the server or in the browser. A page can be rendered to a `Writable` stream such as an HTTP response stream as shown below:
4
-
5
- ```js
6
- var template = require("./template"); // Import ./template.marko
7
-
8
- module.exports = function (req, res) {
9
- res.setHeader("Content-Type", "text/html; charset=utf-8");
10
- template.render({ name: "Frank" }, res);
11
- };
12
- ```
13
-
14
- Marko can also provide you with a `Readable` stream.
15
-
16
- ```js
17
- var template = require("./template"); // Import ./template.marko
18
-
19
- module.exports = function (req) {
20
- // Return a Readable stream for someone to do something with:
21
- return template.stream({ name: "Frank" });
22
- };
23
- ```
24
-
25
- > **ProTip:** Marko also provides server-side framework integrations:
26
- >
27
- > - [express](./express.md)
28
- > - [koa](./koa.md)
29
- > - [fastify](./fastify.md)
30
-
31
- ## UI Bootstrapping
32
-
33
- When a page is rendered on the server, additional code is added to the output HTML to allow the UI to instantly boot in the browser. This additional code allows UI components rendered on the server to be mounted in the browser automatically. For each _top-level_ UI component, Marko will serialize the component's data (including `input` and `state` and any properties added to the UI component instance) so that each top-level UI component can be re-rendered and mounted when the page loads in the browser. Only a "partial" re-render is done for each top-level UI component. That is, when doing the partial re-render in the browser, the DOM is not updated and no virtual DOM is actually produced.
34
-
35
- Marko encodes required information into attributes of rendered HTML elements and it also generates `<script>` tags that will cause UI components to be mounted. The code inside the `<script>` simply registers UI components and when the Marko runtime finally loads, all of the registered UI components will then be mounted. This allows the Marko runtime to be loaded at anytime without causing JavaScript errors.
36
-
37
- ## Bootstrapping Components
38
-
39
- When a server-rendered page loads in the browser it's possible for marko to automatically detect UI components rendered on the server and create and mount them with the correct `state` and `input` in the browser.
40
-
41
- ### Bootstrapping: Lasso
42
-
43
- If you are using [Lasso.js](https://github.com/lasso-js/lasso) then the bootstrapping will happen automatically as long as the JavaScript bundles for your page are included via the `<lasso-body>` tag. A typical HTML page structure will be the following:
44
-
45
- _routes/index/template.marko_
46
-
47
- ```marko
48
- <!DOCTYPE html>
49
- <html lang="en">
50
- <head>
51
- <meta charset="UTF-8">
52
- <title>Marko + Lasso</title>
53
-
54
- <!-- CSS includes -->
55
- <lasso-head/>
56
- </head>
57
- <body>
58
- <!-- Top-level UI component: -->
59
- <app/>
60
-
61
- <!-- JS includes -->
62
- <lasso-body/>
63
- </body>
64
- </html>
65
- ```
66
-
67
- > **ProTip:** We have provided some sample apps to help you get started with Marko + Lasso
68
- >
69
- > - [marko-lasso](https://github.com/marko-js/examples/tree/master/examples/lasso-express)
70
- > - [ui-components-playground](https://github.com/marko-js/examples/tree/master/examples/ui-components-playground)
71
-
72
- ### Bootstrapping: Non-Lasso
73
-
74
- If a JavaScript module bundler other than Lasso is being used then you will need to add some client-side code to bootstrap your application in the browser by doing the following:
75
-
76
- 1. Load/import/require all of the UI components that were rendered on the server (loading the top-level UI component is typically sufficient)
77
- 2. Call `require('marko/components').init()`
78
-
79
- For example, if `client.js` is the entry point for your client-side application:
80
-
81
- _routes/index/client.js_
82
-
83
- ```js
84
- // Load the top-level UI component:
85
- require("./components/app/index");
86
-
87
- // Now that all of the JavaScript modules for the UI component have been
88
- // loaded and registered we can tell marko to bootstrap/initialize the app
89
-
90
- // Initialize and mount all of the server-rendered UI components:
91
- require("marko/components").init();
92
- ```
93
-
94
- > **ProTip:** We have provided some sample apps to help you get started:
95
- >
96
- > - [marko-webpack](https://github.com/marko-js/examples/tree/master/examples/webpack-express)
97
-
98
- # Serialization
99
-
100
- For each _top-level_ UI component, Marko will serialize the component's data (including `input` and `state` and any properties added to the UI component instance) down to the browser. You can control which data gets serialized by implementing [`toJSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) or by reassigning `this.input` in the UI component's `onInput(input, out)` lifecycle method as shown below:
101
-
102
- ```javascript
103
- class {
104
- onInput() {
105
- // Do not serialize any input:
106
- this.input = null;
107
-
108
- // Serialize a new object instead of the provided input:
109
- this.input = {
110
- foo: 'bar'
111
- };
112
- }
113
- }
114
- ```
115
-
116
- > NOTE: Marko does allow cycles in serialized objects and Duplicate objects will only be serialized once
117
-
118
- # Caveats
119
-
120
- There are some caveats associated with rendering a page on the server:
121
-
122
- - The UI component data for top-level UI components must be serializable:
123
- - Only simple objects, numbers, strings, booleans, arrays and `Date` objects are serializable
124
- - Functions are not serializable
125
- - Care should be taken to avoid having Marko serialize too much data
126
- - None of the data in `out.global` is serialized by default, but this can be changed as shown below
127
-
128
- ## Serializing globals
129
-
130
- If there are specific properties on the `out.global` object that need to be serialized then they must be whitelisted when the top-level page is rendered on the server. For example, to have the `out.global.apiKey` and the `out.global.locale` properties serialized you would do the following:
131
-
132
- ```js
133
- template.render(
134
- {
135
- $global: {
136
- serializedGlobals: {
137
- apiKey: true,
138
- locale: true
139
- }
140
- }
141
- },
142
- res
143
- );
144
- ```