From d856fd6af7e4cc762da0af29d689fd73cf08a399 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 23 Sep 2018 21:52:44 -0700 Subject: [PATCH] Auto install elm and create elm.json if needed --- src/assets/ElmAsset.js | 66 ++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/src/assets/ElmAsset.js b/src/assets/ElmAsset.js index c7a8028a345..6ee40f0ed56 100644 --- a/src/assets/ElmAsset.js +++ b/src/assets/ElmAsset.js @@ -1,7 +1,10 @@ const process = require('process'); const Asset = require('../Asset'); +const commandExists = require('command-exists'); const localRequire = require('../utils/localRequire'); const {minify} = require('terser'); +const path = require('path'); +const spawn = require('cross-spawn'); class ElmAsset extends Asset { constructor(name, options) { @@ -10,34 +13,65 @@ class ElmAsset extends Asset { this.hmrPageReload = true; } - async collectDependencies() { - await this.getConfig(['elm.json'], {load: false}); - const dependencies = await this.elm.findAllDependencies(this.name); + async parse() { + let options = { + cwd: path.dirname(this.name) + }; - dependencies.forEach(dependency => { - this.addDependency(dependency, {includedInParent: true}); - }); - } + // If elm is not installed globally, install it locally. + try { + await commandExists('elm'); + } catch (err) { + await localRequire('elm', this.name); + options.pathToElm = path.join( + path.dirname(require.resolve('elm')), + 'bin', + 'elm' + ); + } - async parse() { this.elm = await localRequire('node-elm-compiler', this.name); - const options = { - cwd: process.cwd() - }; + // Ensure that an elm.json file exists, and initialize one if not. + let elmConfig = await this.getConfig(['elm.json'], {load: false}); + if (!elmConfig) { + await this.createElmConfig(options); - if (process.env.NODE_ENV === 'test') { - options.cwd = this.options.rootDir; + // Ensure we are watching elm.json for changes + await this.getConfig(['elm.json'], {load: false}); } if (this.options.minify) { options.optimize = true; } - const compiled = await this.elm.compileToString(this.name, options); + let compiled = await this.elm.compileToString(this.name, options); this.contents = compiled.toString(); } + async collectDependencies() { + let dependencies = await this.elm.findAllDependencies(this.name); + for (let dependency of dependencies) { + this.addDependency(dependency, {includedInParent: true}); + } + } + + async createElmConfig(options) { + let cp = spawn(options.pathToElm || 'elm', ['init']); + cp.stdin.write('y\n'); + + return new Promise((resolve, reject) => { + cp.on('error', reject); + cp.on('close', function(code) { + if (code !== 0) { + return reject(new Error('elm init failed.')); + } + + return resolve(); + }); + }); + } + async generate() { let output = this.contents; @@ -53,7 +87,7 @@ class ElmAsset extends Asset { // Based on: // - http://elm-lang.org/0.19.0/optimize function pack(source) { - const options = { + let options = { compress: { keep_fargs: false, passes: 2, @@ -83,7 +117,7 @@ class ElmAsset extends Asset { rename: false }; - const result = minify(source, options); + let result = minify(source, options); if (result.error) { throw result.error;