1 | # Helix Command Line Interface (`hlx`)
|
2 |
|
3 | ## Status
|
4 |
|
5 | [![codecov](https://img.shields.io/codecov/c/github/adobe/helix-cli.svg)](https://codecov.io/gh/adobe/helix-cli)
|
6 | [![CircleCI](https://img.shields.io/circleci/project/github/adobe/helix-cli/master.svg)](https://circleci.com/gh/adobe/helix-cli/tree/master)
|
7 | [![GitHub license](https://img.shields.io/github/license/adobe/helix-cli.svg)](https://github.com/adobe/helix-cli/blob/master/LICENSE.txt)
|
8 | [![GitHub issues](https://img.shields.io/github/issues/adobe/helix-cli.svg)](https://github.com/adobe/helix-cli/issues)
|
9 | [![LGTM Code Quality Grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/adobe/helix-cli.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/adobe/helix-cli)
|
10 |
|
11 | The Helix Command Line Interface allows web developers to create, develop, and deploy digital experiences using Project Helix
|
12 |
|
13 | ## Installation
|
14 |
|
15 | Install `hlx` as a global command. You need Node 10.13 or newer.
|
16 |
|
17 | ```bash
|
18 | $ npm install -g @adobe/helix-cli
|
19 | ```
|
20 |
|
21 | ## Quick Start
|
22 |
|
23 | ```
|
24 | $ hlx --help
|
25 | hlx <command>
|
26 |
|
27 | Commands:
|
28 | hlx demo <name> [dir] Create example helix project.
|
29 | hlx up [files...] Run a Helix development server
|
30 | hlx build [files..] Compile the template functions and build package
|
31 | hlx package Create Adobe I/O runtime packages
|
32 | hlx deploy Deploy packaged functions to Adobe I/O runtime
|
33 | hlx perf Test performance
|
34 | hlx publish Activate strains in the Fastly CDN and publish the site
|
35 | hlx clean Remove generated files and caches.
|
36 | hlx completion generate bash completion script
|
37 |
|
38 | Options:
|
39 | --version Show version number [boolean]
|
40 | --log-file Log file (use "-" for stdout) [array] [default: "-"]
|
41 | --log-level Log level
|
42 | [string] [choices: "silly", "debug", "verbose", "info", "warn", "error"]
|
43 | [default: "info"]
|
44 | --help Show help [boolean]
|
45 |
|
46 | for more information, find our manual at https://github.com/adobe/helix-cli
|
47 | ```
|
48 |
|
49 | ## Setting up a project
|
50 |
|
51 | ```
|
52 | $ hlx demo <my-cool-project>
|
53 | ```
|
54 |
|
55 | ## Starting development
|
56 |
|
57 | ```
|
58 | $ cd <my-cool-project>
|
59 | $ hlx up
|
60 | ```
|
61 |
|
62 | Just change contents in your project directory and reload `http://localhost:3000` to see the results.
|
63 |
|
64 | ## (Optional) Build artifacts
|
65 |
|
66 | ```
|
67 | # In <my-cool-project>
|
68 | $ hlx build
|
69 | ```
|
70 |
|
71 | ## (Optional) Deploy to Adobe I/O Runtime
|
72 |
|
73 | ### Automatic Deployment
|
74 |
|
75 | By default, Helix will set up automated deployment that deploys whenever a new commit has been pushed to your GitHub code repository. In order to do so, you need a [CircleCI](https://circleci.com) account and generate a [personal API Token](https://circleci.com/account/api).
|
76 |
|
77 | ```
|
78 | # In <my-cool-project>
|
79 | $ hlx deploy \
|
80 | --circleci-auth <personal-api-token> \
|
81 | --wsk-namespace <your-namespace> \
|
82 | --wsk-auth <your-key> \
|
83 | --fastly-auth <key> \
|
84 | --fastly-namespace <serviceid>
|
85 | ```
|
86 |
|
87 | As always, you can keep all parameters in `HLX_CIRCLECI_AUTH`, `HLX_WSK_AUTH`, `HLX_DEV_DEFAULT` and `HLX_FASTLY_AUTH` environment variables if you don't want them in your `.bash_history`.
|
88 |
|
89 | ### One-Shot Deployment
|
90 |
|
91 | Alternatively, you can also perform a one-shot deployment like this:
|
92 |
|
93 | ```
|
94 | # In <my-cool-project>
|
95 | $ hlx deploy --wsk-namespace <your-namespace> --wsk-auth <your-key>
|
96 | [==================================================] analyzing 0.0s
|
97 | [==================================================] packaging 0.0s
|
98 | ✅ packaging completed
|
99 | [==================================================] deploying 0.0s
|
100 | ✅ deployment completed
|
101 | ```
|
102 |
|
103 | Instead of passing `--wsk-auth` as a command line option, you can also set the `HLX_WSK_AUTH` environment variable.
|
104 |
|
105 | ## (Optional) Publish your Site
|
106 |
|
107 | ```
|
108 | # In <my-cool-project>
|
109 | $ hlx publish --fastly-auth <key> --fastly-namespace <serviceid>
|
110 | Publishing [========================================----------] 4.1s
|
111 | ✅ All strains have been published and version 89 is now online.
|
112 | ```
|
113 |
|
114 | ### Purging the Cache upon Publishing
|
115 |
|
116 | Whenever you run `hlx publish`, a new version of your site, with potentially changed code will be made available to visitors. For visitors to see the changes, the Fastly cache needs to be purged. By default, `hlx publish` uses a "Soft purge", which means that the entire content of your website will be marked as outdated (or stale), but not actually removed from the cache. When a request for a cached file that has been marked outdated hits Fastly, Fastly will serve the old version, but fetch a new version in the background. As a result, your site is still as fast as before, *but in order for changes to show up, two requests are needed*.
|
117 |
|
118 | If you want to see your changes faster, at the expense of slower load times right after publishing, use the command `hlx publish --purge hard`, which triggers a hard purge, i.e. removes all cached objects from the Fastly CDN. Doing this on a site with substantial traffic is unwise, but it can be a useful option during development.
|
119 |
|
120 | Finally, if you do not want the cache to be purged at all, run `hlx publish --purge skip`. Your changes will only become visible when the cached objects expire or the cache is cleared in some other way, for instance from the Fastly console or using an API call as part of a more complex continuous deployment set-up.
|
121 |
|
122 | ### Passing Request Parameters
|
123 |
|
124 | Every request parameter is a potential cache-buster and given that modern web application practices liberally append request parameters for tracking purposes or to manage state for client-side applications, **Helix filters out all request parameters by default**.
|
125 |
|
126 | This means, the client side of your application will still be able to access request parameters, but your server(less)-side scripts and templates will not see any parameters.
|
127 |
|
128 | If you need to pass request parameters, you can allow the parameters you need using the `strain.params` configuration. The value of `params` is an array of allowed parameter names.
|
129 |
|
130 | ```yaml
|
131 | strains:
|
132 | - name: default
|
133 | code: https://github.com/adobe/project-helix.io.git#master
|
134 | content: https://github.com/adobe/project-helix.io.git#master
|
135 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
136 | params:
|
137 | - foo
|
138 | - bar
|
139 | ```
|
140 |
|
141 | In the example above, the parameters `foo` and `bar` have been enabled. A request made to `https://www.example.com/index.html?foo=here&bar=there&baz=everywhere` will enable your application to read the `foo` and `bar` parameters. The `baz` parameter and all other parameters will be filtered out.
|
142 |
|
143 | Every allowed parameter value will affect the caching of your site in the CDN.
|
144 |
|
145 | #### Helix-Internal Request Parameters
|
146 |
|
147 | All request parameters starting with `hlx_` will be passed through to the action, so that they can be used for Helix-internal purposes.
|
148 |
|
149 | ### Directory Index
|
150 |
|
151 | The default behavior for directory indexes is to load `index.html` when requesting a path ending with `/`,
|
152 | so that `/foo/bar/` becomes `/foo/bar/index.html`. This setting can be overwritten in `helix-config.yaml`
|
153 | by adding an `index` property:
|
154 |
|
155 | ```yaml
|
156 | strains:
|
157 | - name: default
|
158 | code: https://github.com/adobe/project-helix.io.git#master
|
159 | content: https://github.com/adobe/project-helix.io.git#master
|
160 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
161 | directoryIndex: README.html
|
162 | ```
|
163 |
|
164 | ### Static Content Handling
|
165 |
|
166 | Static content is delivered from the `htdocs` directory of the _code_ repository of the Helix project:
|
167 |
|
168 | ```yaml
|
169 | strains:
|
170 | - name: default
|
171 | code: https://github.com/adobe/project-helix.io.git#master
|
172 | content: https://github.com/adobe/project-helix.io.git#master
|
173 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
174 | ```
|
175 |
|
176 | The same core configuration options (`repo`, `ref`, `root`, and `owner`) are supported for `static` as for `content`.
|
177 |
|
178 | After your next deployment with `hlx publish`, all static content will be served out of the
|
179 | directory `htdocs`. None of this will be visible in the URL, so that no visitor will ever see
|
180 | _htdocs_ in the URL. `https://example.com/favico.ico` would be served from `$REPO/htdocs/favico.ico`.
|
181 |
|
182 | ## Matching Strains to URLs
|
183 |
|
184 | You can define a `url` for each `strain`. This property will make sure that only requests made
|
185 | to this base URL will be mapped to the following URL, enabling patterns like having a production
|
186 | instance on `www.*` and a development instance on `dev.*`.
|
187 |
|
188 | An example configuration could look like this:
|
189 |
|
190 | ```yaml
|
191 | strains:
|
192 | - name: default
|
193 | code: https://github.com/adobe/project-helix.io.git#master
|
194 | content: https://github.com/adobe/project-helix.io.git#master
|
195 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
196 | condition:
|
197 | url: https://www.primordialsoup.life
|
198 |
|
199 | - name: develop
|
200 | code: https://github.com/adobe/project-helix.io.git#dev
|
201 | content: https://github.com/adobe/project-helix.io.git#master
|
202 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
203 | condition:
|
204 | url: https://dev.primordialsoup.life/develop/
|
205 | ```
|
206 |
|
207 | ## Mixing old and new Content
|
208 |
|
209 | Helix can run old and new versions of the same site side by side, and even intermixed. This allows you to gradually upgrade to using Helix.
|
210 |
|
211 | If you want to serve content from another origin server, just add the property `origin` to any strain. `code`, `content`, `directoryIndex`, and most other properties will then be ignored, as all content for that strain will be retrieved from the URL specified in `origin`.
|
212 |
|
213 | You are still able to set strain `conditions` or assign traffic to a strain based on the `url` property.
|
214 |
|
215 | ```yaml
|
216 | strains:
|
217 | - name: default
|
218 | code: https://github.com/adobe/project-helix.io.git#master
|
219 | content: https://github.com/adobe/project-helix.io.git#master
|
220 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
221 |
|
222 | - name: oldcontent
|
223 | origin: https://www.adobe.io
|
224 | condition:
|
225 | url: https://www.primordialsoup.life/content/
|
226 |
|
227 | - name: proxy
|
228 | origin: https://www.adobe.io
|
229 | condition: req.http.host == "proxy.primordialsoup.life"
|
230 | ```
|
231 |
|
232 | In the example above, there are three strains: `default` serves content from `www.primordialsoup.life` using Helix. But all URLs that start with `https://www.primordialsoup.life/content/` will be served from `www.adobe.io`. This means an image that is referenced as `/content/example.png` will be served from the Adobe I/O website.
|
233 |
|
234 | Finally, on `proxy.primordialsoup.life`, all content of the old site is being served. This allows you to easily switch back to an old configuration.
|
235 |
|
236 | ## Development - Serving local content
|
237 |
|
238 | Getting the Helix Development Server to use a local content repository can be done in 2 ways:
|
239 |
|
240 | ### Specify a local content url
|
241 |
|
242 | This is the out-of-the box setup:
|
243 |
|
244 | ```yaml
|
245 | definitions:
|
246 | defaults:
|
247 | - &localRepo "http://localhost/local/default.git"
|
248 |
|
249 | strains:
|
250 | - name: default
|
251 | condition:
|
252 | url: http://localhost:3000/
|
253 | code: *localRepo
|
254 | content: *localRepo
|
255 | static: *localRepo
|
256 | ```
|
257 |
|
258 | The Helix Development server will automatically start a git server that can serve the content from
|
259 | the local repository.
|
260 |
|
261 | ### Use the GitHub emulator
|
262 |
|
263 | When starting the `hlx up` with `--local-repo` argument(s), it instructs the Helix Development Server to
|
264 | start a git server that emulates GitHub repositories for a local git repository. All the strains that
|
265 | have a _content_ or _static_ url that matches the `origin` of emulated repository are internally reconfigured
|
266 | to use the local git server instead.
|
267 |
|
268 | `--local-repo .` is the implicit default. For the simple case, where only one repository is used for code, content and static just do:
|
269 |
|
270 | ```
|
271 | $ hlx up
|
272 | ```
|
273 |
|
274 | which is equivalent to `hlx up --local-repo .`.
|
275 |
|
276 | If you want to explicitly always fetch from GitHub, i.e. ignore the local checkout in the current working directory (or any other checkout specified with `--local-repo`), use `--no-local-repo`:
|
277 |
|
278 | ```
|
279 | $ hlx up --no-local-repo
|
280 | ```
|
281 |
|
282 | ## Passing default action parameters during deploy
|
283 |
|
284 | If the action needs default parameter, they can be specified during `hlx deploy` with the `--default` argument. The argument either takes multiple name/value pairs or json values. They can also be read from environment or json files via the `--default-file` argument.
|
285 |
|
286 | ### use as argument values
|
287 |
|
288 | ```console
|
289 | # arguments with name value pairs
|
290 | hlx deploy --default SECRET value --default ANOTHER foobar
|
291 |
|
292 | # multiple name value pairs
|
293 | hlx deploy --default SECRET value ANOTHER foobar
|
294 |
|
295 | # json argument
|
296 | hlx deploy --default '{"SECRET": "value", "ANOTHER": "foobar"}'
|
297 | ```
|
298 |
|
299 | #### use in environment
|
300 |
|
301 | All `hlx` command line arguments can also be passed via environment variables, prefixed with `HLX_`. Since the `default` parameters need key and value, this is only possible using the json format:
|
302 |
|
303 | (note that the `.env` file is automatically loaded by `hlx`)
|
304 |
|
305 | **.env**
|
306 | ```env
|
307 | HLX_DEFAULT={"SECRET": "value", "ANOTHER": "foobar"}
|
308 | ```
|
309 |
|
310 | ### use via reference to file
|
311 |
|
312 | In addition to the above, the parameters can also be specified using a reference to a json or env file:
|
313 |
|
314 | ```console
|
315 | # reference to env file
|
316 | hlx deploy --default-file secrets.env
|
317 |
|
318 | # reference to json file
|
319 | hlx deploy --default-file ./prod/secrets.json
|
320 | ```
|
321 |
|
322 | **secrets.env**
|
323 | ```env
|
324 | SECRET=value
|
325 | ANOTHER=foobar
|
326 | ```
|
327 |
|
328 | **prod/secrets.json**
|
329 | ```json
|
330 | {
|
331 | "SECRET": "value",
|
332 | "ANOTHER": "foobar"
|
333 | }
|
334 | ```
|
335 |
|
336 | #### use in environment
|
337 |
|
338 | similar to the above, the file reference can also be specified in the environment variables:
|
339 |
|
340 | **.env**
|
341 | ```
|
342 | HLX_DEFAULT_FILE=./prod/secrets.json
|
343 | ```
|
344 |
|
345 | ### Passing default action parameters to the simulator
|
346 |
|
347 | When testing helix locally with `hlx up` the `--dev-default` can be used to specify the action
|
348 | parameters which the simulator should pass to the action.
|
349 |
|
350 | the semantics of the arguments and environment variables is the same as for the `--default` and `--default-file` arguments above.
|
351 |
|
352 | For example, to configure request timeouts:
|
353 |
|
354 | ```
|
355 | $ hlx up --dev-default HTTP_TIMEOUT 2000
|
356 | ```
|
357 |
|
358 | Developers can pass additional action parameters by setting the
|
359 | `HLX_DEV_DEFAULT` environment variable. This must fulfill JSON string formatting;
|
360 | i.e `$HLX_DEV_DEFAULT='{"KEY1":5000, "KEY2":"VALUE2"}'`
|
361 |
|
362 | For a list of known parameters, see [the Helix Pipeline Configuration Parameters documentation](https://github.com/adobe/helix-pipeline/blob/master/docs/secrets.schema.md#secrets-properties)
|
363 |
|
364 |
|
365 | #### Multi Strain Example
|
366 |
|
367 | In the following config, we define 2 repositories:
|
368 |
|
369 | - `defaultRepo` contains the project's code and the main content
|
370 | - `apiRepo` contains additional content; for example the API documentation.
|
371 |
|
372 | We also define 2 strains, one for each purpose.
|
373 |
|
374 | ```yaml
|
375 | definitions:
|
376 | repos:
|
377 | - &defaultRepo https://github.com/helix/welcome.git#master
|
378 | - &apiRepo https://github.com/helix/welcome-api.git#master
|
379 |
|
380 | strains:
|
381 | - name: api
|
382 | condition:
|
383 | url: https://www.project-helix.io/api
|
384 | code: *defaultRepo
|
385 | content: *apiRepo
|
386 | static: *apiRepo
|
387 |
|
388 | - name: default
|
389 | condition:
|
390 | url: https://www.project-helix.io/
|
391 | code: *defaultRepo
|
392 | content: *defaultRepo
|
393 | static: *defaultRepo
|
394 | ```
|
395 |
|
396 | Usually, when invoking `hlx up` without any arguments, the Helix Development Server will serve the
|
397 | content directly from GitHub. This is not suitable for local development. Also, the `api` strain
|
398 | will never be selected, because the `localhost:3000` host header will not match the specified `url`
|
399 | condition.
|
400 |
|
401 | Starting the server with:
|
402 |
|
403 | ```
|
404 | $ hlx up --host=www.project-helix.io
|
405 | ```
|
406 |
|
407 | Solves the latter problem. the `--host` argument internally overrides the `request.header`, so that
|
408 | the strain resolution works as desired.
|
409 |
|
410 | Assume that we also have a local checkout of the `welcome-api`, beside the `welcome` repository:
|
411 |
|
412 | ```
|
413 | projects/
|
414 | ├── welcome/
|
415 | │ ├── helix-config.yaml
|
416 | │ └── index.md
|
417 | └── welcome-api/
|
418 | └── index.md
|
419 | ```
|
420 |
|
421 | We can now launch the server with the respective `--local-repo` arguments:
|
422 |
|
423 | ```
|
424 | $ hlx up --host=www.project-helix.io --local-repo=. --local-repo=../welcome-api
|
425 | ```
|
426 |
|
427 | Now the server will transiently reconfigure the strains, so that the emulated repositories are used.
|
428 |
|
429 | > **Note**: If you turn on `--log-level=debug` you should see log entries for the emulated repositories:
|
430 | ```
|
431 | [hlx] debug: git emulating https://github.com/helix/welcome.git via http://127.0.0.1:52270/helix/github.com--helix--welcome.git#master from './'
|
432 | [hlx] debug: git emulating https://github.com/helix/welcome-api.git via http://127.0.0.1:52270/helix/github.com--helix-welcome-api.git#master from '../welcome-api'
|
433 | ```
|
434 |
|
435 | For convenience, you can also specify the arguments in an `.env` file:
|
436 |
|
437 | ```dotenv
|
438 | HLX_HOST=www.project-helix.io
|
439 | HLX_LOCAL_REPO=., ../welcome-api
|
440 | HLX_LOG_LEVEL=debug
|
441 | ```
|
442 |
|
443 |
|
444 | ## (Recommended) Performance Testing
|
445 |
|
446 | You can (and should) test the performance of your deployed site by running `hlx perf`.
|
447 |
|
448 | The default test will test the entry page of every strain (using the `url`) property, if defined. Additional known URLs can be configured for each strain using the key `urls` (expects an array of URLs).
|
449 |
|
450 | The default test will run from a mid-range mobile phone (Motorola Moto G4), using a regular 3G connection from London, UK. It makes sure that the Lighthouse Accessibility Score and the Lighthouse Performance Score of your site is at least 80.
|
451 |
|
452 | You can set custom performance budgets and change the performance condition for each strain using the `perf` property. If a strain has no `perf` measurement configured, the `perf` configuration of the default strain will be used.
|
453 |
|
454 | An example performance configuration might look like this:
|
455 |
|
456 | ```yaml
|
457 | strains:
|
458 | - name: default
|
459 | code: https://github.com/adobe/project-helix.io.git#master
|
460 | content: https://github.com/adobe/project-helix.io.git#master
|
461 | static: https://github.com/adobe/project-helix.io.git/htdocs#master
|
462 | condition:
|
463 | url: https://www.primordialsoup.life
|
464 | urls:
|
465 | - https://www.primordialsoup.life/README.html
|
466 | perf:
|
467 | device: iPhone8
|
468 | connection: good3G
|
469 | location: Sydney
|
470 | visually_complete_85: 1500
|
471 | lighthouse-best-practices-score: 80
|
472 | ```
|
473 |
|
474 | If the site does not meet all performance criteria you have defined, `hlx perf` will exit with a non-null exit code (the exit code equals the number of failed tests). This allows you to use `hlx perf` as a gating condition in a CI/CD workflow.
|
475 |
|
476 | ### Testing Environment
|
477 |
|
478 | * Possible `device` values are:
|
479 | * `MotorolaMotoG4`
|
480 | * `iPhone5`
|
481 | * `iPhone6`
|
482 | * `iPhone6Plus`
|
483 | * `iPhone7`
|
484 | * `iPhone8`
|
485 | * `Nexus5X`
|
486 | * `Nexus6P`
|
487 | * `GalaxyS5`
|
488 | * `iPad`
|
489 | * `iPadPro`
|
490 | * Possible `connection` values are:
|
491 | * `regular2G`
|
492 | * `good2G`
|
493 | * `slow3G`
|
494 | * `regular3G`
|
495 | * `good3G`
|
496 | * `emergingMarkets`
|
497 | * `regular4G`
|
498 | * `LTE`
|
499 | * `dsl`
|
500 | * `wifi`
|
501 | * `cable`
|
502 | * Possible `location` values are:
|
503 | * `NorthVirginia`
|
504 | * `Frankfurt`
|
505 | * `Sydney`
|
506 | * `Ohio`
|
507 | * `California`
|
508 | * `Oregon`
|
509 | * `Canada`
|
510 | * `Ireland`
|
511 | * `Tokyo`
|
512 | * `Seoul`
|
513 | * `Singapore`
|
514 | * `Mumbai`
|
515 | * `SaoPaulo`
|
516 | * `London`
|
517 |
|
518 | ### Performance Metrics
|
519 |
|
520 | You can set performance budgets against following scores (more is better) and metrics (less is better):
|
521 |
|
522 | * `speed_index`: Speed Index
|
523 | * `visually_complete`: Visually Complete
|
524 | * `visually_complete_85`: 85% Visually Complete
|
525 | * `lighthouse-seo-score`: Lighthouse SEO Score
|
526 | * `lighthouse-best-practices-score`: Lighthouse Best Practices Score
|
527 | * `lighthouse-accessibility-score`: Lighthouse Accessibility Score
|
528 | * `lighthouse-performance-score`: Lighthouse Performance Score
|
529 | * `lighthouse-pwa-score`: Lighthouse Progressive Web App Score
|
530 | * `js-parse-compile`: JS Parse & Compile
|
531 | * `time-to-first-byte`: Time to First Byte
|
532 | * `first-contentful-paint`: First Contentful Paint
|
533 | * `first-meaningful-paint`: First Meaningful Paint
|
534 | * `firstRender`: First Paint
|
535 | * `dom-size`: DOM Element Count
|
536 | * `estimated-input-latency`: Estimated input latency
|
537 | * `consistently-interactive`: Time to Interactive
|
538 | * `first-interactive`: First CPU Idle
|
539 | * `html_body_size_in_bytes`: Total HTML size in bytes
|
540 | * `html_size_in_bytes`: Total HTML transferred
|
541 | * `page_wait_timing`: Response time
|
542 | * `page_size_in_bytes`: Total Page transferred
|
543 | * `page_body_size_in_bytes`: Total Page size in bytes
|
544 | * `asset_count`: Number of requests
|
545 | * `onload`: onLoad
|
546 | * `oncontentload`: onContentLoad
|
547 |
|
548 | #### Structured (JUnit) Performance Reporting
|
549 |
|
550 | By calling `hlx perf` with the option `--junit <file>`, the performance test
|
551 | results will be reported in JUnit-format, which makes it possible to integrate
|
552 | performance result reporting with the CI system performing an automated deployment.
|
553 |
|
554 | For `hlx demo full`, a full CI configuration is created that will run a performance
|
555 | test after a completed deployment, report the per-metric results and mark the build
|
556 | as failed in case metrics are not met.
|
557 |
|
558 | ## Supported Programming Languages
|
559 |
|
560 | Helix allows you to develop experiences using a number of languages in different contexts. The most important languages are:
|
561 |
|
562 | * HTL
|
563 | * JavaScript
|
564 | * JSX
|
565 |
|
566 | Please note that these languages are all executed server-side (or serverless-side, as the code is on Adobe I/O Runtime). In some cases this means that you can move code between client and server with moderate changes.
|
567 |
|
568 | ### Creating Things in Helix with HTL
|
569 |
|
570 | HTL stands for [HTML Template Language and was originally introduced for Adobe Experience Manager](https://docs.adobe.com/content/help/en/experience-manager-htl/using/getting-started/update.html). The implementation in Helix is based on the [HTL Specification](https://github.com/adobe/htl-spec/blob/master/SPECIFICATION.md), but as Helix and the underlying [`htlengine`](https://github.com/adobe/htlengine) are written in JavaScript rather than Java, and as the object model between Helix and AEM is different (check out the [`helix-pipeline` documentation](https://github.com/adobe/helix-pipeline/tree/master/docs) for Helix' domain model), your templates translate roughly rather than directly.
|
571 |
|
572 | You can use HTL within Helix in exactly one context: to create rendering templates for pages or page fragments. Your HTL templates will be compiled by Helix into a JavaScript function, which you can then invoke on Adobe I/O Runtime (through Fastly) or locally (through the Helix Simulator). Rendering templates operate on the current [`context`](https://github.com/adobe/helix-pipeline/blob/master/docs/context.schema.md) and return a HTML string that will be delivered to the browser.
|
573 |
|
574 | HTL templates follow the naming pattern `src/${extension}.htl` or `src/${selector}_${extension}.htl`, for instance `src/html.htl` or `src/footer_html.htl`.
|
575 |
|
576 | Because HTL is a pure declarative templating language, you cannot make any modifications within HTL to change the context. To do that, you need to use JavaScript, which is explained in the next section.
|
577 |
|
578 | ### Creating Things in Helix with JavaScript
|
579 |
|
580 | JavaScript is the universal language that powers Helix and you can use it in a wide array of settings in Helix:
|
581 |
|
582 | 1. to create HTML, JSON, Text, XML, or other documents to be served to the browser (as a template function)
|
583 | 2. to modify and manipulate the [`context`](https://github.com/adobe/helix-pipeline/blob/master/docs/context.schema.md) before it is handed off to a template function (as `pre.js`)
|
584 | 3. to handle requests for forms, web applications, and to create small APIs (as `cgi-bin`)
|
585 | 4. to provide helper functions that can be used elsewhere in Helix (as modules)
|
586 |
|
587 | #### JavaScript Template Functions
|
588 |
|
589 | A JavaScript template functions is a step in the Helix rendering Pipeline that takes the current [`context`](https://github.com/adobe/helix-pipeline/blob/master/docs/context.schema.md) and sets the `context`'s [`response.body`](https://github.com/adobe/helix-pipeline/blob/master/docs/response.schema.md#body). It is a full-powered (serverless) JavaScript function, so you can do whatever you want, include any NPM module that's useful, as long as the function is fast enough to be executed within a couple of seconds.
|
590 |
|
591 | JavaScript template functions are found in files that are follow the naming pattern `src/${extension}.js` or `src/${selector}_${extension}.js`, for instance `src/html.js` or `src/footer_html.js`. Only a number of `extension`s are allowed, including `html`, `json`, `txt`, `xml`, `svg`, and `css`.
|
592 |
|
593 | A minimal functional JavaScript template function must export a `main` function and should set the `context`'s [`response.body`](https://github.com/adobe/helix-pipeline/blob/master/docs/response.schema.md#body) property.
|
594 |
|
595 | ```javascript
|
596 | // exporting `main` is mandatory
|
597 | module.exports.main = (context, action) {
|
598 | context.response = {
|
599 | // setting the body is the purpose of the function
|
600 | body: 'Hello World'
|
601 | };
|
602 | }
|
603 | ```
|
604 |
|
605 | #### JavaScript `pre.js`
|
606 |
|
607 | A JavaScript `pre.js` ("pree-jay-ess") is a collection of JavaScript functions that will be executed by the Helix Pipeline right before the template function gets called. This allows a `pre.js` to prepare the context in a way that makes it easier to use in a template function.
|
608 |
|
609 | In addition, a `pre.js` can use [additional extension points in the pipeline](https://github.com/adobe/helix-pipeline#extension-points), but the step running right before the template function is the most common extension point that gave the `pre.js` its name.
|
610 |
|
611 | `pre.js` files follow the naming pattern `src/${extension}.pre.js` or `src/${selector}_${extension}.pre.js`, for instance `src/html.pre.js` or `src/footer_html.pre.js`. They are the companions of the template functions (in HTL, JavaScript or JSX with the same selector and extension).
|
612 |
|
613 | A minimal `pre.js` must exports a `pre` function and has access to the [`context`](https://github.com/adobe/helix-pipeline/blob/master/docs/context.schema.md) and [`action`](https://github.com/adobe/helix-pipeline/blob/master/docs/action.schema.md) of the pipeline.
|
614 |
|
615 | ```javascript
|
616 | module.exports.pre = (context, action) => {
|
617 | console.log('I am here. You can see this log message in the Adobe I/O Runtime console.');
|
618 | }
|
619 | ```
|
620 |
|
621 | #### JavaScript `cgi-bin`
|
622 |
|
623 | Template functions and `pre.js` have in common that they have no side effects, i.e. they cannot do anything other than change the `context` and render web experiences. This reflects the fact that they get used only to serve `GET` requests and are heavily cached, so that most visitors coming to your site won't actually run code in the Adobe I/O Runtime (which keeps your costs low), but this also means that you should not rely on them when you want actual work done, databases to be written, or emails to be sent.
|
624 |
|
625 | For this, Helix provides you with a simple way of creating, deploying, and running serverless actions that **can** have side-effects. In [the spirit of 1997](https://medium.com/adobetech/2017-will-be-the-year-of-the-cgi-bin-err-serverless-f5d99671bc99), we call it the `cgi-bin`, and it is a place for scripts that are running on your behalf in Adobe I/O Runtime. They get deployed using `hlx deploy` with all your other code, they support multiple parallel deployments, CD, and all the best practices of 2019, but at the ease of development of 1997.
|
626 |
|
627 | In order to create a `cgi-bin` script, all you need to do is to create a `.js` file in the `cgi-bin` directory, such as `hello.js`.
|
628 |
|
629 | ```javascript
|
630 | module.exports.main = (params) => {
|
631 | var name = params.name || 'World';
|
632 | return {payload: 'Hello, ' + name + '!'};
|
633 | }
|
634 | ```
|
635 |
|
636 | This is the ["Hello World" example from Apache OpenWhisk](https://github.com/apache/incubator-openwhisk/blob/master/docs/samples.md#openwhisk-hello-world-example) and it can be used to create a very simple JSON API, which supports POST requests (with a multipart-formdata or JSON body) and GET requests (with URL parameters).
|
637 |
|
638 | #### JavaScript Modules
|
639 |
|
640 | If there are additional helper functions you need in multiple parts of your project, you can simply put them into a JavaScript module below `src`. Make sure to `export` the functions and objects you want to consume in your `cgi-bin`, `pre.js`, or template functions.
|
641 |
|
642 | ### Creating Things in Helix with JSX
|
643 |
|
644 | [JSX is an extension of the ES6 language](https://facebook.github.io/jsx/), originally created by Facebook for the client-side React framework, but, due to its practicality, adopted by [other frameworks](https://mithril.js.org/jsx.html) and is even used [on the server-side](https://nextjs.org).
|
645 |
|
646 | JSX provides a shorthand syntax for creating DOM elements, which makes it well suited for creating templates using multiple components (really just functions) that are re-usable and re-mixable.
|
647 |
|
648 | In Helix, JSX is used for serverless-side rendering of HTML pages or HTML page fragments, making it a language choice for Template Functions and an alternative for [JavaScript Template Functions](#javascript-template-functions).
|
649 |
|
650 | The ability to mix imperative JavaScript code with HTML-generating functions that look almost like real HTML makes JSX an alternative to using HTL with `pre.js`, too, because you can just keep the pre-processing code inside your JSX file.
|
651 |
|
652 | JSX files im Helix follow the naming pattern `src/${extension}.jsx` or `src/${selector}_${extension}.jsx`, for instance `src/html.jsx` or `src/footer_html.jsx`.
|
653 |
|
654 | Like [JavaScript Template Functions](#javascript-template-functions), JSX operates on the `context`, produces `context.response.body` and needs a `main` entry point. A minimal JSX example would look like this:
|
655 |
|
656 | ```jsx
|
657 | function MyComponent(context) {
|
658 | <div>Hello World</div>
|
659 | }
|
660 |
|
661 | module.exports.main = context => {
|
662 | context.response: {
|
663 | // the response body needs to be a string, so taking the `outerHTML` of
|
664 | // the topmost component is a good choice.
|
665 | body: MyComponent(context).outerHTML
|
666 | };
|
667 | };
|
668 | ```
|
669 |
|
670 | # Developing Helix CLI
|
671 |
|
672 | ## Testing
|
673 |
|
674 | You can use `npm run check` to run the tests and check whether your code adheres
|
675 | to the helix-cli coding style.
|