/
ElmAsset.js
134 lines (114 loc) Β· 3.06 KB
/
ElmAsset.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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) {
super(name, options);
this.type = 'js';
}
async parse() {
let options = {
cwd: path.dirname(this.name)
};
// 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'
);
}
this.elm = await localRequire('node-elm-compiler', this.name);
// 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);
// Ensure we are watching elm.json for changes
await this.getConfig(['elm.json'], {load: false});
}
options.debug = !this.options.production;
if (this.options.minify) {
options.optimize = true;
}
let compiled = await this.elm.compileToString(this.name, options);
this.contents = compiled.toString();
if (this.options.hmr) {
let {inject} = await localRequire('elm-hot', this.name);
this.contents = inject(this.contents);
}
}
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;
if (this.options.minify) {
output = pack(output);
}
return {
[this.type]: output
};
// Recommended minification
// Based on:
// - http://elm-lang.org/0.19.0/optimize
function pack(source) {
let options = {
compress: {
keep_fargs: false,
passes: 2,
pure_funcs: [
'F2',
'F3',
'F4',
'F5',
'F6',
'F7',
'F8',
'F9',
'A2',
'A3',
'A4',
'A5',
'A6',
'A7',
'A8',
'A9'
],
pure_getters: true,
unsafe: true,
unsafe_comps: true
},
mangle: true,
rename: false
};
let result = minify(source, options);
if (result.error) {
throw result.error;
}
return result.code;
}
}
}
module.exports = ElmAsset;