]> git.immae.eu Git - github/fretlink/purs-loader.git/blobdiff - src/index.js
Version 3.0.0
[github/fretlink/purs-loader.git] / src / index.js
index 7cf942c912b1493b3e1c05407bcb6e01065c87d1..4c5abd20a1e894ed827c1640b7c0a6c64bac9e12 100644 (file)
@@ -31,31 +31,74 @@ const eol = require('os').EOL
 module.exports = function purescriptLoader(source, map) {
   this.cacheable && this.cacheable();
 
-  const callback = this.async();
-
   const webpackConfig = this.options;
 
+  var cache = webpackConfig.purescriptLoaderCache = webpackConfig.purescriptLoaderCache || {
+    rebuild: false,
+    deferred: [],
+    bundleModules: [],
+    ideServer: null,
+    psModuleMap: null,
+    warnings: [],
+    errors: [],
+    compilationStarted: false,
+    compilationFinished: false,
+    installed: false,
+    srcOption: []
+  };
+
+  const callback = this.async();
+
   const loaderOptions = loaderUtils.getOptions(this) || {};
 
   const srcOption = (pscPackage => {
-    if (pscPackage) {
+    const srcPath = path.join('src', '**', '*.purs');
+
+    const bowerPath = path.join('bower_components', 'purescript-*', 'src', '**', '*.purs');
+
+    if (cache.srcOption.length > 0) {
+      return cache.srcOption;
+    }
+    else if (pscPackage) {
       const pscPackageCommand = 'psc-package';
 
       const pscPackageArgs = ['sources'];
 
+      const loaderSrc = loaderOptions.src || [
+        srcPath
+      ];
+
       debug('psc-package %s %o', pscPackageCommand, pscPackageArgs);
 
-      return spawn(pscPackageCommand, pscPackageArgs).stdout.toString().split(eol).filter(v => v != '').concat(
-        loaderOptions.src || [
-          path.join('src', '**', '*.purs'),
-        ]
-      )
+      const cmd = spawn(pscPackageCommand, pscPackageArgs);
+
+      if (cmd.error) {
+        throw new Error(cmd.error);
+      }
+      else if (cmd.status !== 0) {
+        const error = cmd.stdout.toString();
+
+        throw new Error(error);
+      }
+      else {
+        const result = cmd.stdout.toString().split(eol).filter(v => v != '').concat(loaderSrc);
+
+        debug('psc-package result: %o', result);
+
+        cache.srcOption = result;
+
+        return result;
+      }
     }
     else {
-      return loaderOptions.src || [
-        path.join('bower_components', 'purescript-*', 'src', '**', '*.purs'),
-        path.join('src', '**', '*.purs'),
+      const result = loaderOptions.src || [
+        bowerPath,
+        srcPath
       ];
+
+      cache.srcOption = result;
+
+      return result;
     }
   })(loaderOptions.pscPackage);
 
@@ -65,9 +108,12 @@ module.exports = function purescriptLoader(source, map) {
     pscArgs: {},
     pscBundle: null,
     pscBundleArgs: {},
+    pscIdeClient: null,
+    pscIdeClientArgs: {},
+    pscIdeServer: null,
+    pscIdeServerArgs: {},
     pscIde: false,
     pscIdeColors: loaderOptions.psc === 'psa',
-    pscIdeArgs: {},
     pscPackage: false,
     bundleOutput: 'output/bundle.js',
     bundleNamespace: 'PS',
@@ -80,18 +126,10 @@ module.exports = function purescriptLoader(source, map) {
     src: srcOption
   });
 
-  var cache = webpackConfig.purescriptLoaderCache = webpackConfig.purescriptLoaderCache || {
-    rebuild: false,
-    deferred: [],
-    bundleModules: [],
-    warnings: [],
-    errors: []
-  };
-
-  if (!webpackConfig.purescriptLoaderInstalled) {
+  if (!cache.installed) {
     debugVerbose('installing purs-loader with options: %O', options);
 
-    webpackConfig.purescriptLoaderInstalled = true
+    cache.installed = true;
 
     // invalidate loader cache when bundle is marked as invalid (in watch mode)
     this._compiler.plugin('invalid', () => {
@@ -104,7 +142,11 @@ module.exports = function purescriptLoader(source, map) {
         ideServer: cache.ideServer,
         psModuleMap: cache.psModuleMap,
         warnings: [],
-        errors: []
+        errors: [],
+        compilationStarted: false,
+        compilationFinished: false,
+        installed: cache.installed,
+        srcOption: []
       };
     });
 
@@ -181,8 +223,20 @@ module.exports = function purescriptLoader(source, map) {
     };
 
     const rebuild = () =>
-      ide.rebuild(psModule).catch(error => {
+      ide.rebuild(psModule)
+      .then(() =>
+        toJavaScript(psModule)
+          .then(psModule.load)
+          .catch(psModule.reject)
+      )
+      .catch(error => {
         if (error instanceof ide.UnknownModuleError) {
+          // Store the modules that trigger a recompile due to an
+          // unknown module error. We need to wait until compilation is
+          // done before loading these files.
+
+          cache.deferred.push(psModule);
+
           if (!cache.compilationStarted) {
             cache.compilationStarted = true;
 
@@ -197,28 +251,37 @@ module.exports = function purescriptLoader(source, map) {
                   cache.psModuleMap = map;
                 })
               )
-              .then(() => ide.load(psModule))
-              .then(() => psModule)
+              .then(() =>
+                Promise.map(cache.deferred, psModule =>
+                  ide.load(psModule)
+                    .then(() => toJavaScript(psModule))
+                    .then(psModule.load)
+                )
+              )
+              .catch(error => {
+                cache.deferred[0].reject(error);
+
+                cache.deferred.slice(1).forEach(psModule => {
+                  psModule.reject(new Error('purs-loader failed'));
+                })
+              })
             ;
           }
           else {
-            return Promise.resolve(psModule);
+            // The compilation has started. We must wait until it is
+            // done in order to ensure the module map contains all of
+            // the unknown modules.
           }
         }
         else {
           debug('ide rebuild failed due to an unhandled error: %o', error);
 
-          return Promise.reject(error);
+          psModule.reject(error);
         }
       })
     ;
 
-    connect()
-      .then(rebuild)
-      .then(toJavaScript)
-      .then(psModule.load)
-      .catch(psModule.reject)
-    ;
+    connect().then(rebuild);
   }
   else if (cache.compilationFinished) {
     debugVerbose('compilation is already finished, loading module %s', psModule.name);
@@ -256,7 +319,8 @@ module.exports = function purescriptLoader(source, map) {
         )
         .then(() =>
           Promise.map(cache.deferred, psModule =>
-            toJavaScript(psModule).then(psModule.load)
+            toJavaScript(psModule)
+              .then(psModule.load)
           )
         )
         .catch(error => {