aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/to-javascript.js
diff options
context:
space:
mode:
authoreric thul <thul.eric@gmail.com>2017-02-12 18:05:07 -0500
committereric thul <thul.eric@gmail.com>2017-02-19 12:09:16 -0500
commit8e21ab0ab3f8ba9d129f1cf3b59f87d7a2b5bfc2 (patch)
tree0db1cffab8462d919299ab87eba42200748be632 /src/to-javascript.js
parenta3c358f80f8197d5a1d05e42916cd5593b5b2dd5 (diff)
downloadpurs-loader-8e21ab0ab3f8ba9d129f1cf3b59f87d7a2b5bfc2.tar.gz
purs-loader-8e21ab0ab3f8ba9d129f1cf3b59f87d7a2b5bfc2.tar.zst
purs-loader-8e21ab0ab3f8ba9d129f1cf3b59f87d7a2b5bfc2.zip
Ensure that all imported files are watched
In order to handle the case where a new PureScript file is imported, but fails to compile, the purs-loader now tracks imports for each PureScript file in order to append any additional imports to the resulting JS. This ensures that webpack will watch the new file even before it successfully compiles.
Diffstat (limited to 'src/to-javascript.js')
-rw-r--r--src/to-javascript.js129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/to-javascript.js b/src/to-javascript.js
new file mode 100644
index 0000000..b0b9dda
--- /dev/null
+++ b/src/to-javascript.js
@@ -0,0 +1,129 @@
1'use strict';
2
3const Promise = require('bluebird');
4
5const fs = Promise.promisifyAll(require('fs'));
6
7const path = require('path');
8
9const jsStringEscape = require('js-string-escape');
10
11const difference = require('lodash.difference');
12
13const debug = require('debug')('purs-loader');
14
15const PsModuleMap = require('./PsModuleMap');
16
17function updatePsModuleMap(psModule) {
18 const options = psModule.options;
19
20 const cache = psModule.cache;
21
22 const filePurs = psModule.srcPath;
23
24 if (!cache.psModuleMap) {
25 debug('module mapping does not exist');
26
27 return PsModuleMap.makeMap(options.src).then(map => {
28 cache.psModuleMap = map;
29 return cache.psModuleMap;
30 });
31 }
32 else {
33 return PsModuleMap.makeMapEntry(filePurs).then(result => {
34 const map = Object.assign(cache.psModuleMap, result);
35
36 cache.psModuleMap = map;
37
38 return cache.psModuleMap;
39 });
40 }
41}
42
43 // Reference the bundle.
44function makeBundleJS(psModule) {
45 const bundleOutput = psMoudle.options.bundleOutput;
46
47 const name = psModule.name;
48
49 const srcDir = psModule.srcDir;
50
51 const escaped = jsStringEscape(path.relative(srcDir, bundleOutput));
52
53 const result = `module.exports = require("${escaped}")["${name}"]`;
54
55 return result;
56}
57
58// Replace require paths to output files generated by psc with paths
59// to purescript sources, which are then also run through this loader.
60// Additionally, the imports replaced are tracked so that in the event
61// the compiler fails to compile the PureScript source, we can tack on
62// any new imports in order to allow webpack to watch the new files
63// before they have been successfully compiled.
64function makeJS(psModule, psModuleMap, js) {
65 const requireRE = /require\(['"]\.\.\/([\w\.]+)['"]\)/g;
66
67 const foreignRE = /require\(['"]\.\/foreign['"]\)/g;
68
69 const name = psModule.name;
70
71 const imports = psModuleMap[name].imports;
72
73 var replacedImports = [];
74
75 const result = js
76 .replace(requireRE, (m, p1) => {
77 const escapedPath = jsStringEscape(psModuleMap[p1].src);
78
79 replacedImports.push(p1);
80
81 return `require("${escapedPath}")`;
82 })
83 .replace(foreignRE, () => {
84 const escapedPath = jsStringEscape(psModuleMap[name].ffi);
85
86 return `require("${escapedPath}")`;
87 })
88 ;
89
90 debug('imports %o', imports);
91
92 debug('replaced imports %o', replacedImports);
93
94 const additionalImports = difference(imports, replacedImports);
95
96 debug('additional imports for %s: %o', name, additionalImports);
97
98 const additionalImportsResult = additionalImports.map(import_ => {
99 const escapedPath = jsStringEscape(psModuleMap[import_].src);
100
101 return `var ${import_.replace(/\./g, '_')} = require("${escapedPath}")`;
102 }).join('\n');
103
104 const result_ = result + (additionalImports.length ? '\n' + additionalImportsResult : '');
105
106 return result_;
107}
108
109module.exports = function toJavaScript(psModule) {
110 const options = psModule.options;
111
112 const cache = psModule.cache;
113
114 const bundlePath = path.resolve(options.bundleOutput);
115
116 const jsPath = cache.bundle ? bundlePath : psModule.jsPath;
117
118 const js = fs.readFileAsync(jsPath, 'utf8').catch(() => '');
119
120 const psModuleMap = updatePsModuleMap(psModule);
121
122 debug('loading JavaScript for %s', psModule.name);
123
124 return Promise.props({js: js, psModuleMap: psModuleMap}).then(result =>
125 options.bundle ?
126 makeBundleJS(psModule) :
127 makeJS(psModule, result.psModuleMap, result.js)
128 );
129};