]>
git.immae.eu Git - github/fretlink/purs-loader.git/blob - src/index.js
b151d8285b695a5ee8b5387f73341c72d474ef05
3 const debug_
= require('debug');
5 const debug
= debug_('purs-loader');
7 const debugVerbose
= debug_('purs-loader:verbose');
9 const loaderUtils
= require('loader-utils')
11 const Promise
= require('bluebird')
13 const path
= require('path')
15 const PsModuleMap
= require('./purs-module-map');
17 const compile
= require('./compile');
19 const bundle
= require('./bundle');
21 const ide
= require('./ide');
23 const toJavaScript
= require('./to-javascript');
25 const sourceMaps
= require('./source-maps');
27 const dargs
= require('./dargs');
29 const spawn
= require('cross-spawn').sync
31 const eol
= require('os').EOL
41 compilationStarted: false,
42 compilationFinished: false,
43 compilationFailed: false,
48 module
.exports
= function purescriptLoader(source
, map
) {
49 this.cacheable
&& this.cacheable();
51 const webpackContext
= (this.options
&& this.options
.context
) || this.rootContext
;
53 const callback
= this.async();
55 const loaderOptions
= loaderUtils
.getOptions(this) || {};
57 const srcOption
= (pscPackage
=> {
58 const srcPath
= path
.join('src', '**', '*.purs');
60 const bowerPath
= path
.join('bower_components', 'purescript-*', 'src', '**', '*.purs');
62 if (CACHE_VAR
.srcOption
.length
> 0) {
63 return CACHE_VAR
.srcOption
;
65 else if (pscPackage
) {
66 const pscPackageCommand
= 'psc-package';
68 const pscPackageArgs
= ['sources'];
70 const loaderSrc
= loaderOptions
.src
|| [
74 debug('psc-package %s %o', pscPackageCommand
, pscPackageArgs
);
76 const cmd
= spawn(pscPackageCommand
, pscPackageArgs
);
79 throw new Error(cmd
.error
);
81 else if (cmd
.status
!== 0) {
82 const error
= cmd
.stdout
.toString();
84 throw new Error(error
);
87 const result
= cmd
.stdout
.toString().split(eol
).filter(v
=> v
!= '').concat(loaderSrc
);
89 debug('psc-package result: %o', result
);
91 CACHE_VAR
.srcOption
= result
;
97 const result
= loaderOptions
.src
|| [
102 CACHE_VAR
.srcOption
= result
;
106 })(loaderOptions
.pscPackage
);
108 const options
= Object
.assign({
109 context: webpackContext
,
115 pscIdeClientArgs: {},
117 pscIdeServerArgs: {},
119 pscIdeColors: loaderOptions
.psc
=== 'psa',
121 bundleOutput: 'output/bundle.js',
122 bundleNamespace: 'PS',
132 if (!CACHE_VAR
.installed
) {
133 debugVerbose('installing purs-loader with options: %O', options
);
135 CACHE_VAR
.installed
= true;
137 // invalidate loader CACHE_VAR when bundle is marked as invalid (in watch mode)
138 this._compiler
.plugin('invalid', () => {
139 debugVerbose('invalidating loader CACHE_VAR');
142 rebuild: options
.pscIde
,
145 ideServer: CACHE_VAR
.ideServer
,
146 psModuleMap: CACHE_VAR
.psModuleMap
,
149 compilationStarted: false,
150 compilationFinished: false,
151 compilationFailed: false,
152 installed: CACHE_VAR
.installed
,
157 // add psc warnings to webpack compilation warnings
158 this._compiler
.plugin('after-compile', (compilation
, callback
) => {
159 CACHE_VAR
.warnings
.forEach(warning
=> {
160 compilation
.warnings
.push(warning
);
163 CACHE_VAR
.errors
.forEach(error
=> {
164 compilation
.errors
.push(error
);
171 const psModuleName
= PsModuleMap
.matchModule(source
);
176 load: ({js
, map
}) => callback(null, js
, map
),
177 reject: error
=> callback(error
),
178 srcPath: this.resourcePath
,
179 remainingRequest: loaderUtils
.getRemainingRequest(this),
180 srcDir: path
.dirname(this.resourcePath
),
181 jsPath: path
.resolve(path
.join(options
.output
, psModuleName
, 'index.js')),
184 emitWarning: warning
=> {
185 if (options
.warnings
&& warning
.length
) {
186 CACHE_VAR
.warnings
.push(warning
);
189 emitError: error
=> {
191 CACHE_VAR
.errors
.push(error
);
196 debug('loading %s', psModule
.name
);
198 if (options
.bundle
) {
199 CACHE_VAR
.bundleModules
.push(psModule
.name
);
202 if (CACHE_VAR
.rebuild
) {
203 const connect
= () => {
204 if (!CACHE_VAR
.ideServer
) {
205 CACHE_VAR
.ideServer
= true;
207 return ide
.connect(psModule
)
209 CACHE_VAR
.ideServer
= ideServer
;
212 .then(ide
.loadWithRetry
)
214 if (CACHE_VAR
.ideServer
.kill
) {
215 debug('ide failed to initially load modules, stopping the ide server process');
217 CACHE_VAR
.ideServer
.kill();
220 CACHE_VAR
.ideServer
= null;
222 return Promise
.reject(error
);
227 return Promise
.resolve(psModule
);
231 const rebuild
= () =>
232 ide
.rebuild(psModule
)
234 toJavaScript(psModule
)
235 .then(js
=> sourceMaps(psModule
, js
))
237 .catch(psModule
.reject
)
240 if (error
instanceof ide
.UnknownModuleError
) {
241 // Store the modules that trigger a recompile due to an
242 // unknown module error. We need to wait until compilation is
243 // done before loading these files.
245 CACHE_VAR
.deferred
.push(psModule
);
247 if (!CACHE_VAR
.compilationStarted
) {
248 CACHE_VAR
.compilationStarted
= true;
250 return compile(psModule
)
252 CACHE_VAR
.compilationFinished
= true;
255 Promise
.map(CACHE_VAR
.deferred
, psModule
=>
257 .then(() => toJavaScript(psModule
))
258 .then(js
=> sourceMaps(psModule
, js
))
263 CACHE_VAR
.compilationFailed
= true;
265 CACHE_VAR
.deferred
[0].reject(error
);
267 CACHE_VAR
.deferred
.slice(1).forEach(psModule
=> {
268 psModule
.reject(new Error('purs-loader failed'));
272 } else if (CACHE_VAR
.compilationFailed
) {
273 CACHE_VAR
.deferred
.pop().reject(new Error('purs-loader failed'));
275 // The compilation has started. We must wait until it is
276 // done in order to ensure the module map contains all of
277 // the unknown modules.
281 debug('ide rebuild failed due to an unhandled error: %o', error
);
283 psModule
.reject(error
);
288 connect().then(rebuild
);
290 else if (CACHE_VAR
.compilationFinished
) {
291 debugVerbose('compilation is already finished, loading module %s', psModule
.name
);
293 toJavaScript(psModule
)
294 .then(js
=> sourceMaps(psModule
, js
))
296 .catch(psModule
.reject
);
299 // The compilation has not finished yet. We need to wait for
300 // compilation to finish before the loaders run so that references
301 // to compiled output are valid. Push the modules into the CACHE_VAR to
302 // be loaded once the complation is complete.
304 CACHE_VAR
.deferred
.push(psModule
);
306 if (!CACHE_VAR
.compilationStarted
) {
307 CACHE_VAR
.compilationStarted
= true;
311 CACHE_VAR
.compilationFinished
= true;
314 if (options
.bundle
) {
315 return bundle(options
, CACHE_VAR
.bundleModules
);
319 Promise
.map(CACHE_VAR
.deferred
, psModule
=>
320 toJavaScript(psModule
)
321 .then(js
=> sourceMaps(psModule
, js
))
326 CACHE_VAR
.compilationFailed
= true;
328 CACHE_VAR
.deferred
[0].reject(error
);
330 CACHE_VAR
.deferred
.slice(1).forEach(psModule
=> {
331 psModule
.reject(new Error('purs-loader failed'));
335 } else if (CACHE_VAR
.compilationFailed
) {
336 CACHE_VAR
.deferred
.pop().reject(new Error('purs-loader failed'));
338 // The complation has started. Nothing to do but wait until it is
339 // done before loading all of the modules.