# @soleil-se/app-util@3

Utility functions for WebApps.

## Install

`yarn add @soleil-se/app-util@^3.0.0`

## Migration 1.x.x to 2.x.x

Now using `currentScript` to reference the script element the app is running in to pass data.

Remove appName from the `renderApp` call in `./app_src/server/index.js`. Remove export of `App` and `render` and replace with a call to `render(App)` in `./app_src/client/index.js`.

See [example](#example).

## Usage

```javascript
import { renderApp, getRouteUri, getViewUri, getResourceUri, renderTemplate, isOffline, isOnline } from '@soleil-se/app-util';
```

### `renderApp([config], [settings])` ⇨ `String`

Get HTML string for rendering a client side application. Can be used together with `@soleil-se/app-util/render-vue`, `@soleil-se/app-util/svelte-client` or a custom render function in the client code.

**Returns**: `String` - HTML for rendering an application.

| Param                | Type      | Default                                  | Description                                                                                                                                           |
| -------------------- | --------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| \[config]            | `Object`  | `{}`                                     | Server config or data that will be available in the attribute `data-app` on currentScript. In Vue it will also be available in the `$options` object. |
| \[settings]          | `Object`  | `{}`                                     | Settings object.                                                                                                                                      |
| \[settings.noScript] | `String`  | `”`                                      | HTML that will be rendered when JavaScript is not available.                                                                                          |
| \[settings.selector] | `String`  | `` `[data-portlet-id=”${portletId}”]` `` | Query selector for where the app should be mounted.                                                                                                   |
| \[settings.async]    | `Boolean` | `false`                                  | If the app script should be loaded asynchronously. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/)                |
| \[settings.defer]    | `Boolean` | `true`                                   | If the app script should be loaded after DOM is ready. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/)            |
| \[settings.req]      | `Object`  |                                          | The req object from SiteVision, pass this to optimize browser specific script loading if you have multiple instances of the app.                      |

#### Example

In `app_src/server/index.js`.

```javascript
router.get('/', (req, res) => {
  const data = { foo: 'bar' };
  // Most common usage.
  res.send(renderApp(data));


  // With all settings.
  res.send(renderApp(data, {
    noScript: 'You need JS for this!',
    selector: '#mount_me_here',
    async: false,
    defer: true,
    req,
  }));
});
```

##### **Vue**

In `app_src/client/index.js` or `app_src/main.js`.

```javascript
import render from '@soleil-se/app-util/render-vue';
import App from './App.vue';


render(App);
```

### `getRouteUri(route)` ⇨ `String`

Get URI for a route, same as `getStandaloneUrl` in SiteVision template. <https://developer.sitevision.se/docs/webapps/template#h-Methods>

**Returns**: `String` - URI for route.

| Param | Type     | Description |
| ----- | -------- | ----------- |
| route | `String` | A route.    |

#### Example

```javascript
const routeUri = getRouteUri('/my-route');
```

### `getViewUri(route)` ⇨ `String`

Get URI for a view, same as `getUrl` in SiteVision template. <https://developer.sitevision.se/docs/webapps/template#h-Methods>

**Returns**: `String` - URI for view.

| Param | Type     | Description |
| ----- | -------- | ----------- |
| route | `String` | A route.    |

#### Example

```javascript
const viewUri = getViewUri('/my-route');
```

### `getResourceUri(resource)` ⇨ `String`

Get URI for a resource.

**Returns**: `String` - URI for a resource.

| Param    | Type     | Description |
| -------- | -------- | ----------- |
| resource | `String` | A resource. |

#### Example

```javascript
const resourceUri = getResourceUri('file/in/resource.png');
```

### `renderTemplate(template, [values])` ⇨ `String`

Renders a Underscore template and returns a string. This function is also available inside the template.

**Returns**: `String` - Rendered template

| Param     | Type     | Default | Description          |
| --------- | -------- | ------- | -------------------- |
| template  | `String` |         | Underscore template. |
| \[values] | `Object` | `{}`    | Values.              |

#### Example

**Simple example**

```javascript
const string = renderTemplate('<div><%= foo %></div>', {
  foo: 'bar',
});
```

**Multiple templates**

**views/item.html**

```html
<li>
  <%- name %>
</li>
```

**views/main.html**

```html
<ul>
  <% items.forEach(function(item) { %>
    <%= renderTemplate(itemTemplate, item) %>
  <% }); %>
</ul>
```

```javascript
import { renderTemplate } from '@soleil-se/app-util';
import mainTemplate from './views/main.html';
import itemTemplate from './views/item.html';


const items = [{ name: 'Foo' }, { name: 'Bar' }, { name: 'Baz' }];
const string = renderTemplate(mainTemplate, { items, itemTemplate });
```

> **NOTE** Remember that the second argument must be an object and that objects properties are accessed directly in any child templates!

### `isOffline`

If the webapp is running in offline mode or not. This value is also passed to AppData.

```javascript
if(isOffline) {
  // Do something
}
```

### `isOnline`

If the webapp is running in online mode or not. This value is also passed to AppData.

```javascript
if(isOnline) {
  // Do something
}
```

### `uniqueId`

A unique ID for the WebApp. This value is also passed to AppData.

## AppData

`@soleil-se/app-util/app-data` Data that is available for the WebApp.

```javascript
import AppData from '@soleil-se/app-util/app-data';


// These are avaliable per default:
const { isOffline, isOnline, uniqueId } = AppData;
```

All data passed to the app is available in AppData: index.js

```javascript
res.send(renderApp({ foo: 'bar' }))
```

In app:

```javascript
import AppData from '@soleil-se/app-util/app-data';


console.log(AppData.foo);


// Or descructured
const { foo } = AppData;
console.log(foo);
```

## Svelte

Functions for rendering a Svelte application.

### Server

`@soleil-se/app-util/svelte-server`

#### `render(App, [data], [settings])` ⇨ `String`

Get HTML string for rendering a universal Svelte application. To be used together with `@soleil-se/app-util/svelte-client`.

**Returns**: `String` - HTML for rendering an application.

| Param             | Type      | Default | Description                                                                                                                                |
| ----------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| \[App]            | `Svelte`  |         | Svelte application.                                                                                                                        |
| \[data]           | `Object`  | `{}`    | Server data or config that will be available from `@soleil-se/app-util/app-data`                                                           |
| \[settings]       | `Object`  | `{}`    | Settings object.                                                                                                                           |
| \[settings.async] | `Boolean` | `false` | If the app script should be loaded asynchronously. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/)     |
| \[settings.defer] | `Boolean` | `true`  | If the app script should be loaded after DOM is ready. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/) |
| \[settings.req]   | `Object`  |         | The req object from SiteVision, pass this to optimize browser specific script loading if you have multiple instances of the app.           |

In `app_src/server/index.js` or `app_src/index.js`.

```javascript
import router from 'router';
import { render } from '@soleil-se/app-util/svelte-server';


import App from './App.svelte';


router.get('/', (req, res) => {
  const data = { foo: 'bar' };
  res.send(renderSvelte(App, data));
});
```

#### `renderServer(App, [data])` ⇨ `String`

Get HTML string for a server only rendered Svelte application.

**Returns**: `String` - HTML for rendering an application.

| Param   | Type     | Default | Description                                                                      |
| ------- | -------- | ------- | -------------------------------------------------------------------------------- |
| \[App]  | `Svelte` |         | Svelte application.                                                              |
| \[data] | `Object` | `{}`    | Server data or config that will be available from `@soleil-se/app-util/app-data` |

In `app_src/server/index.js` or `app_src/index.js`.

```javascript
import router from 'router';
import { renderServer } from '@soleil-se/app-util/svelte-server';


import App from './App.svelte';


router.get('/', (req, res) => {
  const data = { foo: 'bar' };
  res.send(renderServer(App, data));
});
```

#### `renderClient(App, [data], [settings])` ⇨ `String`

Get HTML string for a client only rendered Svelte application. Can be used together with `@soleil-se/app-util/svelte-client`.

**Returns**: `String` - HTML for rendering an application.

| Param             | Type      | Default | Description                                                                                                                                |
| ----------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| \[App]            | `Svelte`  |         | Svelte application.                                                                                                                        |
| \[data]           | `Object`  | `{}`    | Server data or config that will be available from `@soleil-se/app-util/app-data`                                                           |
| \[settings]       | `Object`  | `{}`    | Settings object.                                                                                                                           |
| \[settings.async] | `Boolean` | `false` | If the app script should be loaded asynchronously. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/)     |
| \[settings.defer] | `Boolean` | `true`  | If the app script should be loaded after DOM is ready. [Read more about async and defer.](https://flaviocopes.com/javascript-async-defer/) |
| \[settings.req]   | `Object`  |         | The req object from SiteVision, pass this to optimize browser specific script loading if you have multiple instances of the app.           |

In `app_src/server/index.js` or `app_src/index.js`.

```javascript
import router from 'router';
import { renderClient } from '@soleil-se/app-util/svelte-server';


import App from './App.svelte';


router.get('/', (req, res) => {
  const data = { foo: 'bar' };
  res.send(renderSvelte(App, data));
});
```

### Client

`@soleil-se/app-util/svelte-client`

#### `render(App)`

In `app_src/client/index.js` or `app_src/main.js`.

```javascript
import { render } from '@soleil-se/app-util/svelte-client';
import App from './App.svelte';


render(App);
```