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:
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
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 = ❤️
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
// importsconstKoa=require('koa');constserve=require('koa-static');const{resolve}=require('path');const{spawn}=require('child_process');constapp=newKoa();letelcProcess;// I'm not sure how secure is this at allapp.use(serve(`${__dirname}/node_modules`));app.use(serve(`${__dirname}/renderer`));// get the correct electron bin for your platformconstelectron=process.platform==='win32'?resolve('node_modules/.bin','electron.cmd'):resolve('node_modules/.bin','electron');constindexFile=resolve(__dirname,'main/index.js');// after we successfully start our server, then spawn the electron processapp.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 needelcProcess.on('error',onElcError);elcProcess.stdout.on('data',onElcData);elcProcess.on('exit',onElcExit)});functiononElcData(chunk){/*...*/}functiononElcError(err){/*...*/}functiononElcExit(code,signal){/*...*/}
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
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 classexportclassApp{constructor(){this.message="Hello world";this.menuOpen=false;// bind process events to your class functionsipcRenderer.on('get:home:ans',this.setHomePath.bind(this));}// normal life cycle methods available!asyncactivate(){consthome=awaitlocalforage.getItem('home');if (!home){// send a message to the main processipcRenderer.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 servermoduleId:"pages/home.js",title:"Home",nav:true},{route:"contact",name:"contact",moduleId:"pages/contact.js",title:"Contact",nav:true}]);this.router=router;}toggleMenu(){/*...*/}asyncsetHomePath(event,path){/*...*/}}
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.
functioncreateWindow(){// Create the browser window.mainWindow=newBrowserWindow({/*...*/webPreferences:{// call the preload scriptpreload:`${__dirname}/preload.js`,// disable node integration for this windownodeIntegration:false}/*...*/})// and load the index.html of the app.mainWindow.loadURL('http://localhost:45789')/*...*/}
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