systemjs / builder

SystemJS build tool
MIT License
465 stars 122 forks source link

Override text loader when building #782

Closed wawyed closed 7 years ago

wawyed commented 7 years ago

I currently have this configuration:

(function(System) {
  'use strict';

  System.config({
    map: {
      '@angular/core': 'libraries:@angular/core/bundles/core.umd.js',
      '@angular/common': 'libraries:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'libraries:@angular/compiler/bundles/compiler.umd.js',
      '@angular/upgrade': 'libraries:@angular/upgrade/bundles/upgrade.umd.js',
      '@angular/platform-browser': 'libraries:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser/src/facade/browser': 'libraries:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'libraries:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'libraries:@angular/http/bundles/http.umd.js',
      '@angular/forms': 'libraries:@angular/forms/bundles/forms.umd.js',
      rxjs: 'libraries:rxjs',
      lodash: 'libraries:lodash',
      moment: 'libraries:moment',
      jquery: 'libraries:jquery/dist',
      text: 'libraries:systemjs-plugin-text/text.js',
      'element-resize-detector': 'libraries:element-resize-detector/dist'
    },
    packages: {
      app: {
        main: 'main',
        defaultExtension: 'js'
      },
      rxjs: {
        main: 'Rx',
        defaultExtension: 'js'
      },
      lodash: {
        main: 'lodash',
        defaultExtension: 'js'
      },
      moment: {
        main: 'moment',
        defaultExtension: 'js'
      },
      jquery: {
        main: 'jquery',
        defaultExtension: 'js'
      },
      'element-resize-detector': {
        main: 'element-resize-detector',
        defaultExtension: 'js'
      }
    },
    paths: {
      'libraries:': 'shared/libraries/'
    },
    meta: {
      '*.html': {
        loader: 'text'
      }
    }
  });
})(System);

In development I create a libraries folder with the dependencies I need and this works fine. When I have to build the bundle for distribution I created my own fetch function so that I don't need to copy dependencies since I'm using gulp. This looks something like this:


    var builder = new SystemjsBuilder('./src', 'src/systemjs.config.js');

    builder.config({
      defaultJSExtensions: true // Doesn't add the default extension https://github.com/systemjs/builder/issues/728
    });

    builder.bundle('app/main', {
      fetch: function(load, fetch) {
        var loadFilePath = url.parse(load.name).path;

        if (process.platform === 'win32') {
          loadFilePath = loadFilePath.slice(1); //systemjs bundler seems to be adding an extra slash at the beginning of the url for windows.
        }

        var relativeFileName = path.normalize(path.relative(path.resolve('./src'), loadFilePath)),
          tsFile = _.find(files, { relative: relativeFileName });

        if (tsFile) {
          return tsFile.contents.toString();
        }

        load.name = load.name.replace('src/shared/libraries', 'node_modules');
        load.address = load.address.replace('src/shared/libraries', 'node_modules');
        return fetch(load);
      }
    }).then(function(output) {
      // output.source;    // generated bundle source
      // output.sourceMap; // generated bundle source map
      // output.modules;   // array of module names defined in the bundle
      var result = new File({
        cwd: '.',
        base: '.',
        path: 'bundle.js',
        contents: new Buffer(output.source)
      });

      cb(null, result);
    });

This was working fine until I decided to add the text loader. Now I'm getting this error when trying to bundle:

Unhandled rejection (SystemJS) ENOENT: no such file or directory, open 'C:\Users\wawy3\WebUI\src\shared\libraries\systemjs-plugin-text\text.js' Error: ENOENT: no such file or directory, open 'C:\Users\wawy3\WebUI\src\shared\libraries\systemjs-plugin-text\text.js' at Error (native) Error loading C:/Users/wawy3/WebUI/src/shared/libraries/systemjs-plugin-text/text.js

My question is, is there any way I can make the text loader work either via defining my own loader which just points to systemjs-plugin-text or via any other mechanism?

Thanks.

wawyed commented 7 years ago

Is it possible to get an answer on this please?

guybedford commented 7 years ago

I think it sounds like the problem is your custom fetch function is stopping SystemJS builder from being able to "fetch" the text plugin itself? If so a simple exception in the fetch logic might work then?

wawyed commented 7 years ago

@guybedford The problem is that SystemJS builder is not trying to use the fetch function to fetch the loader plugin.

guybedford commented 7 years ago

Ah right, so the fetch hook is applying only for the compiled source and not the plugin itself?

In that case, perhaps just set a map config for the plugin:

builder.bundle('app/main', {
  fetch: ...,
  config: {
    map: {
      text: 'correct/location.js'
    }
  }
}
wawyed commented 7 years ago

Exactly.

I already tried that, the problem is that the path to the plugin is not relative to the folder and doing ../ doesn't work.

guybedford commented 7 years ago

@wawyed it does sound like a path forward though, can you elaborate on those issues? Also you can try using paths instead of map as well.

wawyed commented 7 years ago

My folder structure is as follows:

-root/
  -src/
    -main.ts
    -systemjs.config.js
    //all the other files live here, including the text/html files i want to import.
  -node_modules/

When I run my dev task, the server has the following structure:

-dev/
  -main.js
  -systemjs.config.js
  -shared/
    -libraries/
      -systemjs-plugin-text/
        -text.js
      // any other node_modules that I need go here

Now, when I want to build my distribution bundle I don't want to have to copy files to a temp directory so I use the fetch function to override where systemjs is expecting the files. I do this for two things:

This works fine until I introduce the text loader. SystemJS builder seems to ignore the fetch function for the plugin and try to load for the location specified in systemjs.config.js. Since anything specified in that file has to be relative to the location of systemjs.config.js I have no way to change the config to change the location to node_modules/ (there is no node_modules inside src).

I'm asking for either a way to override the location in gulp/node or a way to provide the loader to the builder or make loaders go to the fetch function to load them first..

Hope this info helps in order to understand my issue better.

wawyed commented 7 years ago

Good news! I manage to do it.

I added the full path in the paths config for dev:

(function(System) {
  'use strict';

  System.config({
    map: {
      '@angular/core': 'libraries:@angular/core/bundles/core.umd.js',
      '@angular/common': 'libraries:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'libraries:@angular/compiler/bundles/compiler.umd.js',
      '@angular/upgrade': 'libraries:@angular/upgrade/bundles/upgrade.umd.js',
      '@angular/platform-browser': 'libraries:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser/src/facade/browser': 'libraries:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'libraries:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'libraries:@angular/http/bundles/http.umd.js',
      '@angular/forms': 'libraries:@angular/forms/bundles/forms.umd.js',
      rxjs: 'libraries:rxjs',
      lodash: 'libraries:lodash',
      moment: 'libraries:moment',
      jquery: 'libraries:jquery/dist',
      'element-resize-detector': 'libraries:element-resize-detector/dist'
    },
    packages: {
      app: {
        main: 'main',
        defaultExtension: 'js'
      },
      rxjs: {
        main: 'Rx',
        defaultExtension: 'js'
      },
      lodash: {
        main: 'lodash',
        defaultExtension: 'js'
      },
      moment: {
        main: 'moment',
        defaultExtension: 'js'
      },
      jquery: {
        main: 'jquery',
        defaultExtension: 'js'
      },
      'element-resize-detector': {
        main: 'element-resize-detector',
        defaultExtension: 'js'
      }
    },
    paths: {
      'libraries:': 'shared/libraries/',
      'textLoader:': 'shared/libraries/systemjs-plugin-text/text.js'
    },
    meta: {
      '*.html': {
        loader: 'textLoader'
      }
    }
  });
})(System);

And for distribution bundle I modified and make it absolute by using file:/// like this:

    builder.config({
      paths: {
        'libraries:': 'shared/libraries/',
        'textLoader': 'file:///' + path.resolve('./node_modules/systemjs-plugin-text/text.js')
      },
      defaultJSExtensions: true // Doesn't add the default extension https://github.com/systemjs/builder/issues/728
    });
guybedford commented 7 years ago

@wawyed glad to hear it is resolved 😀.