├── .gitignore
├── .npmignore
├── .npmrc
├── .travis.yml
├── README.md
├── bin.js
├── example
├── a
│ ├── index.css
│ └── index.js
├── assets
│ └── favicon.ico
├── b
│ ├── index.css
│ └── index.js
├── index.css
├── index.html
├── index.js
├── package.json
├── server.js
└── sw.js
├── index.js
├── lib
├── app.js
├── assets.js
├── build.js
├── compile.js
├── document.js
├── inject.js
├── manifest.js
├── pipeline.js
├── render.js
├── script.js
├── service-worker.js
├── style.js
└── ui.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | package-lock.json
2 | node_modules
3 | .vscode
4 | dist
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | example
2 | .travis.yml
3 | .vscode
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | node_js:
2 | - "10"
3 | - "8"
4 | - "6"
5 | sudo: false
6 | language: node_js
7 | script: "npm run test"
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # jalla
2 | [![stability experimental][stability-badge]][stability-link]
3 | [![npm version][version-badge]][npm-link]
4 | [![build status][travis-badge]][travis-link]
5 | [![downloads][downloads-badge]][npm-link]
6 | [![js-standard-style][standard-badge]][standard-link]
7 |
8 | Jalla is a [Choo][choo] compiler and server in one, making web development fast,
9 | fun and exceptionally performant.
10 |
11 | Jalla is an excellent choice **when static files just don't cut it**. Perhaps
12 | you need to render views dynamically, set custom headers or integrate an API.
13 |
14 | In short, Jalla is a [Koa][koa] server, a [Browserify][browserify] bundler
15 | for scripts and a [PostCSS][postcss] processor for styles. Documents are
16 | compiled using [Documentify][documentify]. And it's all configured for you.
17 |
18 | - [jalla](#jalla)
19 | - [Usage](#usage)
20 | - [Options](#options)
21 | - [Build](#build)
22 | - [Serve](#serve)
23 | - [API](#api)
24 | - [Server Side Rendering](#server-side-rendering)
25 | - [Custom HTML](#custom-html)
26 | - [Prefetching data](#prefetching-data)
27 | - [`ctx.state`](#ctxstate)
28 | - [`ctx.assets`](#ctxassets)
29 | - [Assets](#assets)
30 | - [Manifest](#manifest)
31 | - [Service Workers](#service-workers)
32 | - [Advanced Usage](#advanced-usage)
33 | - [Configuration](#configuration)
34 | - [JavaScript](#javascript)
35 | - [[split-require][split-require]](#split-requiresplit-require)
36 | - [[babelify][babelify]](#babelifybabelify)
37 | - [[brfs][brfs]](#brfsbrfs)
38 | - [[envify][envify]](#envifyenvify)
39 | - [[nanohtml][nanohtml] *(not used in watch mode)*](#nanohtmlnanohtml-not-used-in-watch-mode)
40 | - [[tinyify][tinyify] *(not used in watch mode)*](#tinyifytinyify-not-used-in-watch-mode)
41 | - [CSS](#css)
42 | - [[postcss-url][postcss-url]](#postcss-urlpostcss-url)
43 | - [[postcss-import][postcss-import]](#postcss-importpostcss-import)
44 | - [[autoprefixer][autoprefixer] *(not used in watch mode)*](#autoprefixerautoprefixer-not-used-in-watch-mode)
45 | - [[postcss-csso][postcss-csso] *(not used in watch mode)*](#postcss-cssopostcss-csso-not-used-in-watch-mode)
46 | - [HTML](#html)
47 |
48 | ## Usage
49 | Jalla performs a series of optimizations when compiling your code. By default
50 | it will enter development mode – meaning fast compilation times and automatic
51 | recompilation when files are updated.
52 |
53 | The fastes way to get up and running is by using the CLI and pointing it to your
54 | Choo app entry point. If you name your CSS files `index.css` and place them
55 | adjacent to your script files, they will be automatically detected and included.
56 |
57 | ```bash
58 | $ jalla index.js
59 | ```
60 |
61 | Setting the environment variable `NODE_ENV` to _anything other than_
62 | `development` will cause jalla to perform more expensive compilation and optimizations on your code. Taking longer to compile but making it faster to
63 | run.
64 |
65 | ```bash
66 | $ NODE_ENV=production jalla index.js
67 | ```
68 |
69 | ## Options
70 | - __`--css`__ explicitly include a css file in the build
71 | - __`--service-worker, --sw`__ entry point for a service worker
72 | - __`--base, -b`__ base path where app will be served
73 | - __`--skip, -s`__ skip transform for file/glob (excluding optimizations)
74 | - __`--watch, -w`__ watch files for changes (default in `development`)
75 | - __`--dir, -d`__ output directory, use with [build](#build) and [serve](#serve)
76 | - __`--quiet, -q`__ disable printing to console
77 | - __`--inspect, -i`__ enable the node inspector, accepts a port as value
78 | - __`--port, -p`__ port to use for server
79 |
80 | ## Build
81 | Jalla can write all assets to disk, and then serve them statically. This greatly
82 | increases the server startup times and makes the server more resilient to
83 | failure or sleep. This is especially usefull for serverless plarforms, such as
84 | [now](https://zeit.co/now) or [AWS Lambda](https://aws.amazon.com/lambda/)
85 | et. al.
86 |
87 | By default files will be written to the folder `dist`, but this can be changed
88 | using the `dir` option.
89 |
90 | ```bash
91 | $ NODE_ENV=production jalla build index.js --dir output
92 | ```
93 |
94 | ## Serve
95 | For fast server start up times, use the `serve` command. In serve mode, jalla
96 | will not compile any assets but instead serve built assets produced by the
97 | [build](#build) command.
98 |
99 | By default jalla will look for built files in the `dist` folder. Use the `dir`
100 | option to change this.
101 |
102 | ```
103 | $ NODE_ENV=production jalla serve --dir output
104 | ```
105 |
106 | ## API
107 | After instantiating the jalla server, middleware can be added just like you'd do
108 | with any [Koa][koa] app. The application is an instance of Koa and supports
109 | [all Koa middleware][koa-middleware].
110 |
111 | Just like the [CLI](#usage), the programatic API accepts a Choo app entry point
112 | as it's first argument, followed by options.
113 |
114 | ```javascript
115 | var jalla = require('jalla')
116 | var app = jalla('index.js', {
117 | sw: 'sw.js',
118 | serve: process.env.NODE_ENV === 'production'
119 | })
120 |
121 | app.listen(8080)
122 | ```
123 |
124 | ## Server Side Rendering
125 | For every request that comes in (which accepts HTML and is not an asset), unless
126 | handeled by custom middleware, jalla will try and render an HTML response. Jalla
127 | will await all custom middleware to finish before trying to render a HTML
128 | response. If the response has been redirected (i.e. calling `ctx.redirect`) or
129 | if a value has been assigned to `ctx.body` jalla will not render any HTML
130 | response.
131 |
132 | During server side rendering a `status` code can be added to the state which
133 | will be used for the HTTP response. This is usefull to set proper `404` or error
134 | codes.
135 |
136 | ```javascript
137 | var mount = require('koa-mount')
138 | var jalla = require('jalla')
139 | var app = jalla('index.js')
140 |
141 | // only allow robots in production
142 | app.use(mount('/robots.txt', function (ctx, next) {
143 | ctx.type = 'text/plain'
144 | ctx.body = `
145 | User-agent: *
146 | Disallow: ${process.env.NODE_ENV === 'production' ? '' : '/'}
147 | `
148 | }))
149 |
150 | app.listen(8080)
151 | ```
152 |
153 | ### Custom HTML
154 | By default, Jalla will render your app in an empty HTML document, injecting
155 | assets and initial state. You can override the default empty document by adding
156 | an `index.html` file adjacent to the application entry file.
157 |
158 | You can inform jalla of where in the document you'd like to mount the
159 | application by exporting the Choo app instance after calling `.mount()`.
160 |
161 | ```javascript
162 | // app.js
163 | module.exports = app.mount('#app')
164 | ```
165 |
166 | ```html
167 |
168 |
169 |
170 |
171 |
172 | ```
173 |
174 | ### Prefetching data
175 | Often times you'll need to fetch some data to render the application views. For
176 | this, jalla will expose an array, `prefetch`, on the application state. Jalla
177 | will render the app once and then wait for the promises in the array to resolve
178 | before issuing another render pass using the state generated the first time.
179 |
180 | ```javascript
181 | // store.js
182 | var fetch = require('node-fetch')
183 |
184 | module.exports = function (state, emitter) {
185 | state.data = state.data || null
186 |
187 | emitter.on('fetch', function () {
188 | var request = fetch('/my/api')
189 | .then((res) => res.json())
190 | .then(function (data) {
191 | state.data = data
192 | emitter.emit('render')
193 | })
194 |
195 | // expose request to jalla during server side render
196 | if (state.prefetch) state.prefetch.push(request)
197 | })
198 | }
199 | ```
200 |
201 | Apart from `prefetch`, jalla also exposes the HTTP `req` and `res` objects.
202 | They can be usefull to read cookies or set headers. Writing to the response
203 | stream, however, is not recommended.
204 |
205 | ### `ctx.state`
206 | The data stored in the state object after all middleware has run will be used
207 | as state when rendering the HTML response. The resulting application state will
208 | be exposed to the client as `window.initialState` and will be automatically
209 | picked up by Choo. Using `ctx.state` is how you bootstrap your client with
210 | server generated content.
211 |
212 | Meta data for the page being rendered can be added to `ctx.state.meta`. A
213 | `` tag will be added to the header for every property therein.
214 |
215 |
216 | Example decorating ctx.state
217 |
218 | ```javascript
219 | var geoip = require('geoip-lite')
220 |
221 | app.use(function (ctx, next) {
222 | if (ctx.accepts('html')) {
223 | ctx.state.location = geoip.lookup(ctx.ip)
224 | }
225 | return next()
226 | })
227 | ```
228 |
229 |
230 |
231 | ### `ctx.assets`
232 | Compiled assets are exposed on `ctx.assets` as a `Map` object. The assets hold
233 | data such as the asset url, size and hash. There's also a `read` method for
234 | retreiving the asset buffer.
235 |
236 |
237 | Example adding Link headers for all JS assets
238 |
239 | ```javascript
240 | app.use(function (ctx, next) {
241 | if (!ctx.accepts('html')) return next()
242 |
243 | for (let [id, asset] of ctx.assets) {
244 | if (id !== 'bundle.js' && /\.js$/.test(id)) {
245 | ctx.append('Link', `<${asset.url}>; rel=preload; as=script`)
246 | }
247 | }
248 |
249 | return next()
250 | })
251 | ```
252 |
253 |
254 |
255 | ## Assets
256 | Static assets can be placed in an `assets` folder adjacent to the Choo app entry
257 | file. Files in the assets folder will be served statically by jalla.
258 |
259 | ## Manifest
260 | A bare-bones application manifest is generated based on the projects
261 | `package.json`. You can either place a custom `manifest.json` in the
262 | [assets](#assets) folder or you can generate one using a custom middleware.
263 |
264 | ## Service Workers
265 | By supplying the path to a service worker entry file with the `sw` option, jalla
266 | will build and serve it's bundle from that path.
267 |
268 | Registering a service worker with a Choo app is easily done using
269 | [choo-service-worker][choo-service-worker].
270 |
271 | ```javascript
272 | // index.js
273 | app.use(require('choo-service-worker')('/sw.js'))
274 | ```
275 |
276 | And then starting jalla with the `sw` option.
277 |
278 | ```bash
279 | $ jalla index.js --sw sw.js
280 | ```
281 |
282 | Information about application assets are exposed to the service worker during
283 | its build and can be accessed as an environment variable.
284 |
285 | - __`process.env.ASSET_LIST`__ a list of URLs to all included assets
286 |
287 |
288 |
289 | Example service worker
290 |
291 | ```javascript
292 | // index.json
293 | var choo = require('choo')
294 | var app = choo()
295 |
296 | app.route('/', require('./views/home'))
297 | app.use(require('choo-service-worker')('/sw.js'))
298 |
299 | module.exports = app.mount('body')
300 | ```
301 |
302 | ```javascript
303 | // sw.js
304 | var CACHE_KEY = process.env.npm_package_version
305 | var FILES = ['/'].concat(process.env.ASSET_LIST)
306 |
307 | self.addEventListener('install', function oninstall (event) {
308 | // cache landing page and all assets once service worker is installed
309 | event.waitUntil(
310 | caches
311 | .open(CACHE_KEY)
312 | .then((cache) => cache.addAll(FILES))
313 | .then(() => self.skipWaiting())
314 | )
315 | })
316 |
317 | self.addEventListener('activate', function onactivate (event) {
318 | // clear old caches on activate
319 | event.waitUntil(clear().then(function () {
320 | if (!self.registration.navigationPreload) return self.clients.claim()
321 | // enable navigation preload
322 | return self.registration.navigationPreload.enable().then(function () {
323 | return self.clients.claim()
324 | })
325 | }))
326 | })
327 |
328 | self.addEventListener('fetch', function onfetch (event) {
329 | // try and perform fetch, falling back to cached response
330 | event.respondWith(caches.open(CACHE_KEY).then(async function (cache) {
331 | try {
332 | var cached = await cache.match(req)
333 | var response = await (event.preloadResponse || self.fetch(event.request))
334 | if (response.ok && req.method.toUpperCase() === 'GET') {
335 | await cache.put(req, response.clone())
336 | }
337 | return response
338 | } catch (err) {
339 | if (cached) return cached
340 | return err
341 | }
342 | }))
343 | })
344 |
345 | // clear application cache
346 | // () -> Promise
347 | function clear () {
348 | return caches.keys().then(function (keys) {
349 | var caches = keys.filter((key) => key !== CACHE_KEY)
350 | return Promise.all(keys.map((key) => caches.delete(key)))
351 | })
352 | }
353 | ```
354 |
355 |
356 |
357 | ## Advanced Usage
358 | If you need to jack into the compilation and build pipeline of jalla, there's a
359 | `pipeline` utility attached to the app instance. The pipline is labeled so that
360 | you can hook into any specific step of the compilation to add or inspect assets.
361 |
362 | Using the method `get` you can retrieve an array that holds the differnt steps
363 | associated with a specific compilation step. You may push your own functions to
364 | this array to have them added to the pipeline.
365 |
366 | The labels on the pipeline are:
367 | - __`scripts`__ compiles the main bundle and any dynamic bundles
368 | - __`styles`__ detect CSS files and compile into single bundle
369 | - __`assets`__ locate static assets
370 | - __`manifest`__ generate manifest.json file unless one already exists
371 | - __`service-worker`__ compile the service worker
372 | - __`build`__ write files to disk
373 |
374 | The functions in the pipeline have a similar signature to that of Choo routes.
375 | They are instantiated with a state object and a function for emitting events.
376 | A pipline function should return a function which will be called whenever jalla
377 | is compiling the app. The pipline steps are called in series, and have access
378 | to the assets and dependencies of all prior steps.
379 |
380 | ```javascript
381 | var path = require('path')
382 | var jalla = require('jalla')
383 | var csv = require('csvtojson')
384 | var app = jalla('index.js')
385 |
386 | // convert and include data.csv as a JSON file
387 | app.pipeline.get('assets').push(function (state, emit) {
388 | return async function (cb) {
389 | if (state.assets.has('data.json')) return cb()
390 | emit('progress', 'data.json')
391 | var json = await csv.fromFile(path.resolve(state.entry, 'data.csv'))
392 | emit('asset', 'data.json', Buffer.from(JSON.stringify(json)), {
393 | mime: 'application/json
394 | })
395 | cb()
396 | }
397 | })
398 |
399 | if (process.env.BUILD) {
400 | app.build(path.resolve(__dirname, 'dist'), function (err) {
401 | if (err) console.error(err)
402 | process.exit(err ? 1 : 0)
403 | })
404 | } else {
405 | app.listen(8080)
406 | }
407 | ```
408 |
409 | ## Configuration
410 | The bundling is handled by tested and reliable tools which can be configured
411 | just as you are used to.
412 |
413 | ### JavaScript
414 | Scripts are compiled using [Browserify][browserify]. Custom transforms can be
415 | added using the [`browserify.transform`][browserify-transform] field in your
416 | `package.json` file.
417 |
418 |
419 | Example browserify config
420 |
421 | ```javascript
422 | // package.json
423 | "browserify": {
424 | "transform": [
425 | ["aliasify", {
426 | "aliases": {
427 | "d3": "./shims/d3.js",
428 | "underscore": "lodash"
429 | }
430 | }]
431 | ]
432 | }
433 | ```
434 |
435 |
436 |
437 |
438 | Included Browserify optimizations
439 |
440 | ##### [split-require][split-require]
441 | Lazily load parts of your codebase. Jalla will transform dynamic imports into
442 | calls to split-require automatically (using a
443 | [babel plugin][babel-dynamic-import]), meaning you only have to call
444 | `import('./some-file')` to get bundle splitting right out of the box.
445 |
446 | ##### [babelify][babelify]
447 | Run [babel][babel] on your sourcecode. Will respect local `.babelrc` files for
448 | configuring the babel transform.
449 |
450 | The following babel plugins are added by default:
451 | - __[babel-plugin-dynamic-import-split-require][babel-dynamic-import]__
452 | transform dynamic import calls to split-require.
453 | - __[babel-preset-env][babel-preset-env]__: read [`.browserlist`][browserslist]
454 | file to configure which babel plugins to support the browsers listed therein.
455 | *Not used in watch mode*.
456 |
457 | ##### [brfs][brfs]
458 | Inline static assets in your application using the Node.js `fs` module.
459 |
460 | ##### [envify][envify]
461 | Use environment variables in your code.
462 |
463 | ##### [nanohtml][nanohtml] *(not used in watch mode)*
464 | Choo-specific optimization which transpiles html templates for increased browser
465 | performance.
466 |
467 | ##### [tinyify][tinyify] *(not used in watch mode)*
468 | A wide suite of optimizations and minifications removing unused code,
469 | significantly reducing file size.
470 |
471 |
472 |
473 | ### CSS
474 | CSS files are looked up and included automaticly. Whenever a JavaScript module
475 | is used in your application, jalla will try and find an adjacent `index.css`
476 | file in the same location. Jalla will also respect the `style` field in a
477 | modules `package.json` to determine which CSS file to include.
478 |
479 | All CSS files are transpiled using [PostCSS][PostCSS]. To add PostCSS plugins,
480 | either add a `postcss` field to your `package.json` or, if you need to
481 | conditionally configure PostCSS, create a `.postcssrc.js` in the root of your
482 | project. See [postcss-load-config][postcss-load-config] for details.
483 |
484 |
485 | Example PostCSS config
486 |
487 | ```javascript
488 | // package.json
489 | "postcss": {
490 | "plugins": {
491 | "postcss-custom-properties": {}
492 | }
493 | }
494 | ```
495 |
496 | ```javascript
497 | // .postcssrc.js
498 | module.exports = config
499 |
500 | function config (ctx) {
501 | var plugins = []
502 | if (ctx.env !== 'development') {
503 | plugins.push(require('postcss-custom-properties'))
504 | }
505 | return { plugins }
506 | }
507 | ```
508 |
509 |
510 |
511 |
512 | The included PostCSS plugins
513 |
514 | ##### [postcss-url][postcss-url]
515 | Rewrite URLs and copy assets from their source location. This means you can
516 | reference e.g. background images and the like using relative URLs and it'll just
517 | work™.
518 |
519 | ##### [postcss-import][postcss-import]
520 | Inline files imported with `@import`. Works for both local files as well as for
521 | files in `node_modules`, just like it does in Node.js.
522 |
523 | ##### [autoprefixer][autoprefixer] *(not used in watch mode)*
524 | Automatically add vendor prefixes. Respects [`.browserlist`][browserslist] to
525 | determine which browsers to support.
526 |
527 | ##### [postcss-csso][postcss-csso] *(not used in watch mode)*
528 | Cleans, compresses and restructures CSS for optimal performance and file size.
529 |
530 |
531 |
532 | ### HTML
533 | Jalla uses [Documentify][documentify] to compile server-rendered markup.
534 | Documentify can be configured in the `package.json` (see Documentify
535 | documentation). By default, jalla only applies HTML minification using
536 | [posthtml-minifier][posthtml-minifier].
537 |
538 |
539 | Example Documentify config
540 |
541 | ```javascript
542 | // package.json
543 | "documentify": {
544 | "transform": [
545 | ["./my-transform.js"]
546 | ]
547 | }
548 | ```
549 |
550 | ```javascript
551 | // my-transform.js
552 | var hyperstream = require('hstream')
553 |
554 | module.exports = transform
555 |
556 | function transform () {
557 | return hyperstream({
558 | 'html': {
559 | // add a class to the root html element
560 | class: 'page-root'
561 | },
562 | 'meta[name="viewport"]': {
563 | // instruct Mobile Safari to expand under the iPhone X notch
564 | content: 'width=device-width, initial-scale=1, viewport-fit=cover'
565 | },
566 | head: {
567 | // add some tracking script to the header
568 | _appendHtml: `
569 |
570 |
576 | `
577 | }
578 | })
579 | }
580 | ```
581 |
582 |
583 |
584 | [choo]: https://github.com/choojs/choo
585 | [bankai]: https://github.com/choojs/bankai
586 | [koa]: https://github.com/koajs/koa
587 | [koa-middleware]: https://github.com/koajs/koa/wiki
588 | [postcss]: https://github.com/postcss/postcss
589 | [documentify]: https://github.com/stackhtml/documentify
590 | [browserify]: https://github.com/substack/node-browserify
591 | [split-require]: https://github.com/goto-bus-stop/split-require
592 | [babelify]: https://github.com/babel/babelify
593 | [brfs]: https://github.com/browserify/brfs
594 | [envify]: https://github.com/hughsk/envify
595 | [nanohtml]: https://github.com/choojs/nanohtml
596 | [tinyify]: https://github.com/browserify/tinyify
597 | [babel-dynamic-import]: https://github.com/goto-bus-stop/babel-plugin-dynamic-import-split-require
598 | [babel]: https://babeljs.io
599 | [babel-preset-env]: https://github.com/babel/babel-preset-env
600 | [browserslist]: https://github.com/browserslist/browserslist
601 | [postcss-import]: https://github.com/postcss/postcss-import
602 | [postcss-url]: https://github.com/postcss/postcss-url
603 | [autoprefixer]: https://github.com/postcss/autoprefixer
604 | [postcss-csso]: https://github.com/lahmatiy/postcss-csso
605 | [browserify-transform]: https://github.com/browserify/browserify#browserifytransform
606 | [postcss-load-config]: https://github.com/michael-ciniawsky/postcss-load-config#readme
607 | [posthtml-minifier]: https://github.com/Rebelmail/posthtml-minifier
608 | [choo-service-worker]: https://github.com/choojs/choo-service-worker
609 | [cloudflare-cache-guide]: https://support.cloudflare.com/hc/en-us/articles/200172366-How-do-I-cache-everything-on-a-URL-
610 | [cccpurge]: https://github.com/jallajs/cccpurge
611 |
612 | [stability-badge]: https://img.shields.io/badge/stability-experimental-orange.svg?style=flat-square
613 | [stability-link]: https://nodejs.org/api/documentation.html#documentation_stability_index
614 | [version-badge]: https://img.shields.io/npm/v/jalla.svg?style=flat-square
615 | [npm-link]: https://npmjs.org/package/jalla
616 | [travis-badge]: https://img.shields.io/travis/jallajs/jalla/master.svg?style=flat-square
617 | [travis-link]: https://travis-ci.org/jallajs/jalla
618 | [downloads-badge]: https://img.shields.io/npm/dm/jalla.svg?style=flat-square
619 | [standard-badge]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square
620 | [standard-link]: https://github.com/feross/standard
621 |
--------------------------------------------------------------------------------
/bin.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | process.title = 'jalla'
4 |
5 | var path = require('path')
6 | var chalk = require('chalk')
7 | var assert = require('assert')
8 | var dedent = require('dedent')
9 | var getPort = require('get-port')
10 | var minimist = require('minimist')
11 | var jalla = require('./index')
12 |
13 | var COMMANDS = ['start', 'build', 'serve']
14 |
15 | var argv = minimist(process.argv.slice(2), {
16 | alias: {
17 | 'service-worker': 'sw',
18 | dir: 'd',
19 | quiet: 'q',
20 | inspect: 'i',
21 | skip: 's',
22 | base: 'b',
23 | watch: 'w',
24 | port: 'p',
25 | help: 'h',
26 | version: 'v'
27 | },
28 | default: {
29 | port: process.env.PORT || 8080
30 | },
31 | boolean: [
32 | 'help',
33 | 'quiet',
34 | 'version'
35 | ]
36 | })
37 |
38 | if (argv.help) {
39 | console.log('\n', dedent`
40 | ${chalk.dim('usage')}
41 | ${chalk.cyan.bold('jalla')} [command] [opts]
42 |
43 | ${chalk.dim('commands')}
44 | start start server and compile assets (default)
45 | build build assets to disk
46 | serve start server and serve built assets
47 |
48 | ${chalk.dim('options')}
49 | --css entry point for CSS
50 | --service-worker, --sw entry point for service worker
51 | --base, -b base path where app will be mounted
52 | --skip, -s skip transform for file/glob (excluding optimizations)
53 | --watch, -w enable watch mode (default in development)
54 | --dir, -d output directory, use with ${chalk.bold('build')} and ${chalk.bold('serve')}
55 | --quiet, -q disable printing to console
56 | --inspect, -i enable node inspector, accepts port
57 | --port, -p server port
58 | --version, -v print version
59 | --help, -h show this help text
60 |
61 | ${chalk.dim('examples')}
62 | ${chalk.bold('start development server')}
63 | jalla index.js
64 |
65 | ${chalk.bold('start development server with CSS and service worker entries')}
66 | jalla index.js --sw sw.js --css index.css
67 |
68 | ${chalk.bold('build and start production server')}
69 | NODE_ENV=production jalla build index.js && jalla serve index.js
70 | `)
71 | process.exit(0)
72 | }
73 |
74 | if (argv.version) {
75 | console.log(require('./package.json').version)
76 | process.exit(0)
77 | }
78 |
79 | var entry = argv._[argv._.length - 1]
80 | var command = argv._.length > 1 ? argv._[0] : 'start'
81 | assert(COMMANDS.includes(command), `jalla: command "${command}" not recognized`)
82 | assert(entry, 'jalla: entry file should be supplied')
83 |
84 | if (argv.inspect) {
85 | if (typeof argv.inspect === 'number') process.debugPort = argv.inspect
86 | process.kill(process.pid, 'SIGUSR1')
87 | }
88 |
89 | var opts = {}
90 | if (argv.css) opts.css = argv.css
91 | if (argv.base) opts.base = argv.base
92 | if (argv.quiet) opts.quiet = argv.quiet
93 | if (command === 'serve') opts.serve = argv.dir || true
94 | if (argv['service-worker']) opts.sw = argv['service-worker']
95 | if (typeof argv.watch !== 'undefined') opts.watch = Boolean(argv.watch)
96 |
97 | if (command === 'build') {
98 | opts.watch = false
99 | const app = jalla(path.resolve(process.cwd(), entry), opts)
100 | const dir = typeof argv.dir === 'string' ? argv.dir : 'dist'
101 | app.build(path.resolve(process.cwd(), dir)).then(function () {
102 | process.exit(0)
103 | }, function () {
104 | process.exit(1)
105 | })
106 | } else {
107 | const app = jalla(path.resolve(process.cwd(), entry), opts)
108 | getPort({ port: argv.port || 8080 }).then(function (port) {
109 | app.listen(port)
110 | })
111 | }
112 |
--------------------------------------------------------------------------------
/example/a/index.css:
--------------------------------------------------------------------------------
1 | /* @define ViewA */
2 |
3 | .ViewA {
4 | background-color: pink;
5 | }
6 |
--------------------------------------------------------------------------------
/example/a/index.js:
--------------------------------------------------------------------------------
1 | var html = require('choo/html')
2 |
3 | module.exports = view
4 |
5 | function view (state, emit) {
6 | return html`
7 |
8 |