DEV Community

Angel Daniel Munoz Gonzalez
Angel Daniel Munoz Gonzalez

Posted on

Aurelia Script

Last year Aurelia introduced a version that can be put in a script tag and you are ready to go! it was named aurelia-script

GitHub logo aurelia / script

The home for Aurelia's concatenated script-tag-ready build.

aurelia-script

Join the chat at https://gitter.im/aurelia/discuss

This repo is the home for Aurelia's concatenated script-tag-ready build.

To keep up to date on Aurelia, please visit and subscribe to the official blog and our email list. We also invite you to follow us on twitter. If you have questions, please join our community on Gitter or use stack overflow. Documentation can be found in our developer hub.

Getting started with Aurelia Script

Simple examples

In the good old day, you chuck in a script tag into your html and start writing app. Aurelia Script is a way to help you return to that, with Aurelia. Simply add:

  <script src='https://unpkg.com/aurelia-script@1.5.2'></script>
Enter fullscreen mode Exit fullscreen mode

into your main html and you are ready to go, like the following:

   <script>
    au
      .start({
        debug: true,
        // root: 'app.js', // can be ommitted, default is
Enter fullscreen mode Exit fullscreen mode

Aurelia is conventions based, you need an <name>.html file with a template tag and a <name>.js file with a class and that's it you now have a component to be used anywhere else. the fact that Aurelia is conventions based, means that
you can go from concept to prototype to feature with the same files you started with.

Setting up with Electron

When playing with this I found out that the router finds for these convention based files in the root of the server, using the dynamic imports, (import()) so this brings two things to the table, if you want to use aurelia-script you need to take into consideration that it is meant for browsers with dynamic imports support, and the other... is that loading from file:// won't work at all!

this can be fixed quite easily, just run a small static server to serve your content, I chose koa.js but you can easily use a static server package out there

GitHub logo AngelMunoz / AuExplorer

A small Proof of concept of an aurelia-script electron mixed app

AuExplorer

A small Proof of concept of an aurelia-script electron mixed app

pnpm install # or npm
pnpm start # or npm

Aurelia + Electron = ❤️ Screenshot

It's a small sample and was done quick and dirty but to me shows how easy is to get started with aurelia-script since aurelia is based on conventions if you need to grow out of the single script, you will do that quite easy




first of all our code in the index.js file at the root is pretty simple

// imports
const Koa = require('koa');
const serve = require('koa-static');
const { resolve } = require('path');
const { spawn } = require('child_process');

const app = new Koa();
let elcProcess;

// I'm not sure how secure is this at all
app.use(serve(`${__dirname}/node_modules`));
app.use(serve(`${__dirname}/renderer`));

// get the correct electron bin for your platform
const electron = process.platform === 'win32' ? resolve('node_modules/.bin', 'electron.cmd') : resolve('node_modules/.bin', 'electron');
const indexFile = resolve(__dirname, 'main/index.js');

// after we successfully start our server, then spawn the electron process
app.listen(45789, '127.0.0.1', () => {
  // you could also add argv arguments if you need
  // like [indexFile, ...process.argv.slice(2)]
  elcProcess = spawn(electron, [indexFile], {});
  // bind process monitoring if you need
  elcProcess.on('error', onElcError);
  elcProcess.stdout.on('data', onElcData);
  elcProcess.on('exit', onElcExit)
});

function onElcData(chunk) {/*...*/}

function onElcError(err) {/*...*/}

function onElcExit(code, signal) {/*...*/}
Enter fullscreen mode Exit fullscreen mode

nothing fancy just your every other day node server.

Inside the renderer we have our aurelia app which starts pretty much like the one I showed you in the codesandbox above

<script src="/aurelia-script/dist/aurelia_router.umd.js"></script>
<script src="/localforage/dist/localforage.js"></script>
<script src="/dayjs/dayjs.min.js"></script>
<script>
  const aurelia = new au.Aurelia();
  aurelia
    .use
    .standardConfiguration()
    .developmentLogging();
  aurelia
    .start()
    .then(() => aurelia.setRoot(`app.js`, document.body))
    .catch(ex => {
      document.body.textContent = `Bootstrap error: ${ex}`;
    });
</script>
Enter fullscreen mode Exit fullscreen mode

you might be thinking why do I need to manually call these libraries! iugh! it's 2019! well I just tried this as a proof of concept, so there might be better options on how to do this, perhaps parcel?, or you can just build your app and spit the bundle in there, but the principal idea of this sample is to go for simplicity and just put in some stuff together and just work it out!

other thing to have into consideration is that I turned off node integration for the sample and added a preload script to add the ipcRenderer to the window object so I could just send back and forth messages to the main process (more on that later on).

Let's take a look to our app.js file

// simple class
export class App {
  constructor() {
    this.message = "Hello world";
    this.menuOpen = false;
    // bind process events to your class functions
    ipcRenderer.on('get:home:ans', this.setHomePath.bind(this));
  }

  // normal life cycle methods available!
  async activate() {
    const home = await localforage.getItem('home');
    if (!home) {
      // send a message to the main process
      ipcRenderer.send('get:home');
    }
  }

  // just like in any other aurelia app!
  configureRouter(config, router) {

    config.options.pushState = true;

    config.map([
      {
        route: ["", "home"],
        name: "home",
        // relative to the root of the server
        moduleId: "pages/home.js",
        title: "Home",
        nav: true
      },
      {
        route: "contact",
        name: "contact",
        moduleId: "pages/contact.js",
        title: "Contact",
        nav: true
      }
    ]);
    this.router = router;
  }

  toggleMenu() {/*...*/}

  async setHomePath(event, path) {/*...*/}
}
Enter fullscreen mode Exit fullscreen mode

now you may wondering, how can the ipcRenderer be just there? no require no import no anything, well that's because we have a small preload script that does that for us, I'll show the createWindow function at the index.js in the main directory and omit the rest.


function createWindow() {
  // Create the browser window.
  mainWindow = new BrowserWindow({
    /*...*/
    webPreferences: {
      // call the preload script
      preload: `${__dirname}/preload.js`,
      // disable node integration for this window
      nodeIntegration: false
    }
    /*...*/
  })

  // and load the index.html of the app.
  mainWindow.loadURL('http://localhost:45789')
  /*...*/
}

Enter fullscreen mode Exit fullscreen mode

and then in our preload script

const { ipcRenderer } = require('electron');
window.ipcRenderer = ipcRenderer;
window.PATH_DIVIDER = process.platform === 'win32' ? '\\' : '/';
Enter fullscreen mode Exit fullscreen mode

you can use this script to expose node internals if you need them, like the inAppPurchase API
but in my short thinking you should be able to accomplish most of the things by just using the ipc-inter-process communication.

Thoughts

Well this was a cool thing to experiment and try on, it feels really great to just pull a script tag and have all the power of aurelia and it's conventions at your hands!
for example if you wanted all of the power of vue, the most ideal is to have vue files but when you use a script tag, that's not really a possibility you would need to change your vue components into other syntax which doesn't match the same experience of the vue files, I feel the same applies to other frameworks out there at the moment.

Extra

if you wonder how Dependecy injection and bindable decorators you would normally use fit in aurelia-script you can check this sample out

https://codesandbox.io/s/92vmpwnjjo

Please share your thoughts and comments below and have an awesome week!

Oldest comments (2)

Collapse
 
timfish profile image
Tim Fish

this can be fixed quite easily, just run a small static server to serve your content

It might be an easy fix for experimentation and Aurelia and Electron are great but you should not ship a production Electron app with a built in web server simply because aurelia-script doesn't work on file://.

Most of time you'll be lucky and port 45789 will be available on the machine but Aurelia works perfectly well with Electron without exposing a server on localhost.

Collapse
 
tunaxor profile image
Angel Daniel Munoz Gonzalez

Yes, this was intended to test aurelia-script within electron and any potential gotchas (like the file:// part). I just wanted to share my experience about using it

I don't intend anyone to ship aurelia-script to production and I'm well aware of some aurelia + electron solutions