steal-conditional
Version:
Conditional loading
322 lines (223 loc) • 9.38 kB
Markdown
@page StealJS.guides.substitution_conditional_loading Substitution Conditional Loading
@parent StealJS.guides
@outline 0
@body
<!-- hack! -->
<style>.contents { display: none; }</style>
StealJS supports conditional module loading through the [steal-conditional](https://github.com/stealjs/steal-conditional) extension;
2 types of conditionals are currently supported, string substitution and [StealJS.guides.boolean_conditional_loading boolean].
In this guide, we'll build a small demo that uses the string substitution conditional syntax to import a random translation of the famous "Hello, World!".
## Install Prerequisites
### Window Setup
1. Install [NodeJS](https://nodejs.org/).
2. Install Chocolatey, Python, Windows SDK, and Visual Studio as described [here](http://stealjs.com/docs/guides.ContributingWindows.html).
### Linux / Mac Setup
1. Install [NodeJS](https://nodejs.org/).
## Setting up a new project
### Create a new project folder
Create a new folder for your project and then run `npm init`. Answer all questions with their defaults.
```
> mkdir substitution-demo
> cd substitution-demo
> npm init
```
### Create and host the main page
Create _index.html_ with:
```html
<html lang="en">
<head>
<style>
#header { text-align: center; margin-top: 50px; }
</style>
</head>
<body>
<h1 id="header">Hello, World!</h1>
</body>
</html>
```
Next install and run a local fileserver. [http-server](https://www.npmjs.com/package/http-server) handles our basic needs. We'll install it locally and then and it to our npm scripts:
```
> npm install http-server --save
```
Next, edit your `package.json` so that the start script looks like:
```json
"scripts": {
"start": "http-server -c-1"
}
```
This allows us to start the server with:
```
> npm start
```
Open [http://127.0.0.1:8080/](http://127.0.0.1:8080/). You should see the *Hello, World!* test.
> Before proceeding kill the development server so we can install some dependencies. Use cmd+c on Mac or ctrl+c on Windows or Linux/BSD.
### Install the application dependencies
Installing these dependencies gives us everything we need to build our application.
```
> npm install steal steal-tools steal-conditional --save-dev
```
### Set up steal-conditional
Next, configure StealJS to load the `steal-conditional` extension as a [configuration dependency](https://stealjs.com/docs/npm.html#packagestealconfigdependencies); in your `package.json` add the following:
```json
{
"name": "substitution-demo",
"steal": {
"configDependencies": [
"./node_modules/steal-conditional/conditional.js"
]
}
}
```
@highlight 3-7
Now restart your server; you can keep it on while you develop the rest of the application.
```
> npm start
```
## Import your first module
### Create the module
Create _index.js_ with the following:
```js
document.getElementById("header").textContent = "Hello, World!";
```
Nothing interesting here, we grab the element with the `header` id and then set its `textContent` property to `Hello, World!`.
### Use steal.js in your page
Update _index.html_ with:
```html
<html lang="en">
<head>
<style>
#header { text-align: center; margin-top: 50px; }
</style>
</head>
<body>
<h1 id="header">Hello, World!</h1>
<script src="./node_modules/steal/steal.js"></script>
</body>
</html>
```
@highlight 10
Also, since we are setting the `textContent` property using JavaScript, go ahead
and remove the `Hello, World!` from _index.html_.
```html
<html lang="en">
<head>
<style>
#header { text-align: center; margin-top: 50px; }
</style>
</head>
<body>
<h1 id="header"></h1>
<script src="./node_modules/steal/steal.js"></script>
</body>
</html>
```
@highlight 9
Reload _index.html_ to see your changes.
## Create the translation files
Our goal is to import a random translation of `Hello, World!` and set it to the
`textContent` of the `h1` tag we added to _index.html_.
Create a folder name **locale**, and add the following, each translation in its
own module:
```js
// substitution-demo/locale/en.js
export default { helloWorld: "Hello, World!" };
```
```js
// substitution-demo/locale/es.js
export default { helloWorld: "¡Hola Mundo!" };
```
```js
// substitution-demo/locale/hi.js
export default { helloWorld: "नमस्ते दुनिया" };
```
Next, we need to import these modules in _index.js_ and randomly pick a specific
translation to use its value to populate the `h1` tag in _index.html_.
We could import each individual module and then write a simple algorithm to pick one
of the translation values, in our example, that's an ok solution since we only have 3
translation modules, but you can imagine how annoying it would be to do the same with
100 or even more modules.
### The string substitution syntax
Add the following to the _index.js_ file we created before:
```js
import i18n from "locale/#{lang}";
document.getElementById("header").textContent = i18n.helloWorld;
```
@highlight 1
This syntax might be already familiar and the reason is that it resembles the [ES2015 Template Literals](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals) syntax,
with the difference that the character before the curly braces is a `#` sign.
The name between the curly braces (`lang` in our example) is a module name, called condition module, the `steal-conditional` extension will load it first and grab [its default export](https://developer.mozilla.org/en/docs/web/javascript/reference/statements/export#Using_the_default_export); if the value is not a `string` it will throw an error, otherwise this value is used to replace the module name along with the `#` sign and the curly braces.
Let's say, `lang`'s default export value is the string `'foo'`, the conditional import in _index.js_ would be interpolated to:
```js
import i18n from "locale/foo";
```
> It is also possible for the conditional module to define multiple conditions via the `.` modifier:
> ```js
> import "locale/#{lang.helloWorld}";
> ```
> See `steal-conditional`'s [README](https://github.com/stealjs/steal-conditional/blob/master/README.md) for more details.
### Create the condition module
Create _lang.js_ with:
```js
const locales = ['en', 'es', 'hi'];
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
}
export default locales[getRandomInt(0, locales.length)];
```
The condition module creates a constant that holds the possible translation files to use,
in our example there are 3 possible modules, then, the `getRandomInt` helper is defined,
this function returns a random number between the `min` argument and `max`.
Finally, `getRandomInt` is used to export a value of the `locales` array.
Reload _index.html_ to see your changes.

If you reload _index.html_ a couple more times, you should see the other translations as well:

Pretty cool, don't you think?
> Showing a random language is done here for demonstration purposes, in most real world applications you'd want to use [the preferred language of the user](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language).
## Build a production app
Now that we've created our application we need to share it with the public. To do this we'll create a build that will concat our JavaScript and styles down to only one file, each, for faster page loads in production.
### Build the app and switch to production
When we first installed our initial dependencies for myhub, one of those was *steal-tools*. steal-tools is a set of tools that helps with bundling assets for production use.
In your package.json `"scripts"` section add:
```json
{
"scripts": {
...
"build": "steal-tools"
}
}
```
And then you can run:
```
> npm run build
```
To use the production artifacts rather than the development files we need to update our index.html to load them.
Update _index.html_ with:
```html
<html lang="en">
<head>
<style>
#header { text-align: center; margin-top: 50px; }
</style>
</head>
<body>
<h1 id="header"></h1>
<script src="./dist/steal.production.js"></script>
</body>
</html>
```
@highlight 10
By using `steal.production.js` instead of `steal.js` StealJS will know to load the production files we just built.
### A bundle for each conditional module
During the build, `steal-conditional` will detect the possible variations and `steal-tools` will create separate individual bundles for each variation.
If we take a look at the artifacts created during the build process

We can see how each of the locale modules we create gets its own bundle.
Finally, reload _index.html_ to see your changes:
