]>
git.immae.eu Git - github/fretlink/purs-loader.git/blob - src/index.js
f90a21886065b1be7f808cfec4bc3483cf0f6a3e
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
33 module
.exports
= function purescriptLoader(source
, map
) {
34 this.cacheable
&& this.cacheable();
36 const webpackConfig
= this.options
;
38 var cache
= webpackConfig
.purescriptLoaderCache
= webpackConfig
.purescriptLoaderCache
|| {
46 compilationStarted: false,
47 compilationFinished: false,
52 const callback
= this.async();
54 const loaderOptions
= loaderUtils
.getOptions(this) || {};
56 const srcOption
= (pscPackage
=> {
57 const srcPath
= path
.join('src', '**', '*.purs');
59 const bowerPath
= path
.join('bower_components', 'purescript-*', 'src', '**', '*.purs');
61 if (cache
.srcOption
.length
> 0) {
62 return cache
.srcOption
;
64 else if (pscPackage
) {
65 const pscPackageCommand
= 'psc-package';
67 const pscPackageArgs
= ['sources'];
69 const loaderSrc
= loaderOptions
.src
|| [
73 debug('psc-package %s %o', pscPackageCommand
, pscPackageArgs
);
75 const cmd
= spawn(pscPackageCommand
, pscPackageArgs
);
78 throw new Error(cmd
.error
);
80 else if (cmd
.status
!== 0) {
81 const error
= cmd
.stdout
.toString();
83 throw new Error(error
);
86 const result
= cmd
.stdout
.toString().split(eol
).filter(v
=> v
!= '').concat(loaderSrc
);
88 debug('psc-package result: %o', result
);
90 cache
.srcOption
= result
;
96 const result
= loaderOptions
.src
|| [
101 cache
.srcOption
= result
;
105 })(loaderOptions
.pscPackage
);
107 const options
= Object
.assign({
108 context: webpackConfig
.context
,
114 pscIdeClientArgs: {},
116 pscIdeServerArgs: {},
118 pscIdeColors: loaderOptions
.psc
=== 'psa',
120 bundleOutput: 'output/bundle.js',
121 bundleNamespace: 'PS',
131 if (!cache
.installed
) {
132 debugVerbose('installing purs-loader with options: %O', options
);
134 cache
.installed
= true;
136 // invalidate loader cache when bundle is marked as invalid (in watch mode)
137 this._compiler
.plugin('invalid', () => {
138 debugVerbose('invalidating loader cache');
140 cache
= webpackConfig
.purescriptLoaderCache
= {
141 rebuild: options
.pscIde
,
144 ideServer: cache
.ideServer
,
145 psModuleMap: cache
.psModuleMap
,
148 compilationStarted: false,
149 compilationFinished: false,
150 installed: cache
.installed
,
155 // add psc warnings to webpack compilation warnings
156 this._compiler
.plugin('after-compile', (compilation
, callback
) => {
157 cache
.warnings
.forEach(warning
=> {
158 compilation
.warnings
.push(warning
);
161 cache
.errors
.forEach(error
=> {
162 compilation
.errors
.push(error
);
169 const psModuleName
= PsModuleMap
.matchModule(source
);
174 load: ({js
, map
}) => callback(null, js
, map
),
175 reject: error
=> callback(error
),
176 srcPath: this.resourcePath
,
177 remainingRequest: loaderUtils
.getRemainingRequest(this),
178 srcDir: path
.dirname(this.resourcePath
),
179 jsPath: path
.resolve(path
.join(options
.output
, psModuleName
, 'index.js')),
182 emitWarning: warning
=> {
183 if (options
.warnings
&& warning
.length
) {
184 cache
.warnings
.push(warning
);
187 emitError: error
=> {
189 cache
.errors
.push(error
);
194 debug('loading %s', psModule
.name
);
196 if (options
.bundle
) {
197 cache
.bundleModules
.push(psModule
.name
);
201 const connect
= () => {
202 if (!cache
.ideServer
) {
203 cache
.ideServer
= true;
205 return ide
.connect(psModule
)
207 cache
.ideServer
= ideServer
;
210 .then(ide
.loadWithRetry
)
212 if (cache
.ideServer
.kill
) {
213 debug('ide failed to initially load modules, stopping the ide server process');
215 cache
.ideServer
.kill();
218 cache
.ideServer
= null;
220 return Promise
.reject(error
);
225 return Promise
.resolve(psModule
);
229 const rebuild
= () =>
230 ide
.rebuild(psModule
)
232 toJavaScript(psModule
)
233 .then(js
=> sourceMaps(psModule
, js
))
235 .catch(psModule
.reject
)
238 if (error
instanceof ide
.UnknownModuleError
) {
239 // Store the modules that trigger a recompile due to an
240 // unknown module error. We need to wait until compilation is
241 // done before loading these files.
243 cache
.deferred
.push(psModule
);
245 if (!cache
.compilationStarted
) {
246 cache
.compilationStarted
= true;
248 return compile(psModule
)
250 cache
.compilationFinished
= true;
253 PsModuleMap
.makeMap(options
.src
).then(map
=> {
254 debug('rebuilt module map after unknown module forced a recompilation');
256 cache
.psModuleMap
= map
;
260 Promise
.map(cache
.deferred
, psModule
=>
262 .then(() => toJavaScript(psModule
))
263 .then(js
=> sourceMaps(psModule
, js
))
268 cache
.deferred
[0].reject(error
);
270 cache
.deferred
.slice(1).forEach(psModule
=> {
271 psModule
.reject(new Error('purs-loader failed'));
277 // The compilation has started. We must wait until it is
278 // done in order to ensure the module map contains all of
279 // the unknown modules.
283 debug('ide rebuild failed due to an unhandled error: %o', error
);
285 psModule
.reject(error
);
290 connect().then(rebuild
);
292 else if (cache
.compilationFinished
) {
293 debugVerbose('compilation is already finished, loading module %s', psModule
.name
);
295 toJavaScript(psModule
)
296 .then(js
=> sourceMaps(psModule
, js
))
298 .catch(psModule
.reject
);
301 // The compilation has not finished yet. We need to wait for
302 // compilation to finish before the loaders run so that references
303 // to compiled output are valid. Push the modules into the cache to
304 // be loaded once the complation is complete.
306 cache
.deferred
.push(psModule
);
308 if (!cache
.compilationStarted
) {
309 cache
.compilationStarted
= true;
313 cache
.compilationFinished
= true;
316 if (options
.bundle
) {
317 return bundle(options
, cache
.bundleModules
);
321 PsModuleMap
.makeMap(options
.src
).then(map
=> {
322 debug('rebuilt module map after compilation');
324 cache
.psModuleMap
= map
;
328 Promise
.map(cache
.deferred
, psModule
=>
329 toJavaScript(psModule
)
330 .then(js
=> sourceMaps(psModule
, js
))
335 cache
.deferred
[0].reject(error
);
337 cache
.deferred
.slice(1).forEach(psModule
=> {
338 psModule
.reject(new Error('purs-loader failed'));
344 // The complation has started. Nothing to do but wait until it is
345 // done before loading all of the modules.