aurelia / bundler

A library for bundling JavaScript, HTML and CSS for use with SystemJS.
MIT License
37 stars 25 forks source link

Specify output path outside baseURL #101

Closed RomkeVdMeulen closed 7 years ago

RomkeVdMeulen commented 8 years ago

I'm working on integrating some Aurelia components in an existing Java EE project built with Maven. The Aurelia code lives in src/main/frontend, while the build directory for Maven is target/projectname-version. As a workaround, I have Aurelia built in src/main/frontend/dist and have Maven copy that to target/projectname-version/frontend, but that's not exactly ideal.

I've been able to have most of the build tasks build the app into the Maven build dir directly, even though it's several levels up from the Aurelia root dir. The only blocker is Aurelia bundler: I can't configure the output dir, and if I try to specify the Maven build dir in the bundle config, I get:

Unable to calculate canonical name to bundle file:///../project/target/projectname-version/frontend/bundles/aurelia.js. Ensure that this module sits within the baseURL or a wildcard path config.

Even if I could get that to work, I'd have to fix the injected config so that the built app loads the bundle from the correct URL.

What I'd much prefer would be if I could somehow configure bundler with something like:

var config = {
  baseURL: '.',
  configPath: './config.js',
  buildPath: '../../../target/projectname-version/frontend'
};

What do you think? Is this a feature worth considering?

RomkeVdMeulen commented 8 years ago

For anybody interested, I've created a workaround for now: build the bundles in the Aurelia dir, copy to target dir, then delete generated files in Aurelia dir. Here's an example, based on gulp config like you'd find in the skeletons. Requires NPM modules mkdirp, ncp and del.

var bundles = {
  bundleDir: "frontend/bundles",
  bundles: {
    "frontend/bundles/aurelia": {
      "includes": [
        ..
      ]
  }
};

var paths = {
  target: "../../../target/projectname-version/"
};

var bundleConfig = {
    baseURL: '.',
    bundles: bundles.bundles
};

gulp.task('bundle', function(callback) {
  // Check whether already exists (alternatively use --force in your bundle config)
  fs.access(paths.target + bundles.bundleDir, fs.F_OK, function(err) {
    if (!err) {
      return callback();
    }

    // Have to make the build-dir myself, see #102
    mkdirp(bundles.bundleDir, function() {
      bundler.bundle(bundleConfig).then(function() {
        var bundleRoot = bundles.bundleDir.split("/")[0];
        ncp(bundleRoot, paths.target + bundleRoot, function(err) {
          if (err) {
            throw err;
          }
          del([bundleRoot + "/**"], function() {
            callback();
          });
        })
      });
    });
  });
});
EisenbergEffect commented 8 years ago

@ahmedshuhel This seems like a reasonable feature. I think it's been requested several times. What do you think?

ahmedshuhel commented 8 years ago

We cannot allow it outside of the baseURL because it will conflict with the inject feature. A bundle file is treated as a "normal" module by SystemJS. We calculate the canonical name of the bundle file and use that name in the config.js. However, if somebody does not use inject feature and wants to place the bundle file in some arbitrary path, it makes sense to allow/implement the feature.

EisenbergEffect commented 8 years ago

Perhaps we can check the configuration to see if the correct combination of settings is present, and if so, allow it. If not, we can raise a helpful error message explaining the situation.

RomkeVdMeulen commented 8 years ago

The calculation of the canonical path seems to assume that the bundle will be served directly from the filesystem, which isn't the case here. The calculated canonical path is still correct, even though it doesn't match the output path I'd like to specify. E.g. if:

var bundleConfig = {
  baseURL: '.',
  bundles: [
    "frontend/bundles/aurelia": {
      ...
    }
  ]
};

then the bundle should still be loaded from frontend/bundles/aurelia.js at runtime, even if I choose to build it to ../../../target/projectname-version/frontend/bundles/aurelia.js, package it in a WAR and upload it to an application server. I'd still like to be able to use inject in this scenario.

ahmedshuhel commented 8 years ago

In this case we may allow overriding the injection name and output path via configuration. This will by pass calculating canonical name and use the override instead. The user will be responsible for calculating the correct canonical name. Does this solve the problem? cc @EisenbergEffect

EisenbergEffect commented 8 years ago

It seems ok to me. Let's see what @RomkeVdMeulen thinks.

RomkeVdMeulen commented 8 years ago

Looks good. Would it be possible if you specify output path but not injection name to fall back to the current calculation for the injection name? See previous example.

ahmedshuhel commented 8 years ago

I will let you know if that is possible.

MeirionHughes commented 8 years ago

Any progress on this?

gregorydickson commented 8 years ago

This is the exact issue I am running into. +1. I'm going to try with the CLI.

Jfy6Y3TtV698a646 commented 7 years ago

+1

For me, I'm happy with the stock approach of building to dist then exporting to export, however to keep with the convention for structuring a site's assets, I'd like to finally deploy the bundle to scripts.

If I mess around with changing the base directory away from dist, the config.js file gets poluted with relative paths, and/or fails to inject and then tries to pull the app files directly from the site rather than from the bundle.

However, if I build as usual, then change the config.js * path from dist to scripts, and manually move the bundle, then everything works perfectly.

Obviously I can just continue to do just this via a shell script as part of the CI build, however it'd be much cleaner to have a working set of config options that just do this for me.

deviprsd commented 7 years ago

Even I have been bugging @AStoker about something like this. This should be implemented asap.

AStoker commented 7 years ago

Is this something that someone can submit a PR for if they think they have a solution?

deviprsd commented 7 years ago

I'll look into it and see if I can submit a PR

ivands commented 7 years ago

Please i need this in my life.

ahmedshuhel commented 7 years ago

@ivands 😃 And Hopefully you will get it tomorrow.

deviprsd commented 7 years ago

@ahmedshuhel really?

ahmedshuhel commented 7 years ago

Working on it. Will be pushing to master.

deviprsd commented 7 years ago

This still happening?

ahmedshuhel commented 7 years ago

PR is merged. Published a beta version. Please do install with npm install aurelia-bundler@beta and let us know. Implemented as described here

 var config = {
  force: true,
   baseURL: '.',
   configPath: './config.js',
   outputPath: './abc/def/',
    bundles: {
       "dist/app-build": {
         "includes": [
           "[**/*.js]",
           "**/*.html!text",
           "**/*.css!text"
         ],
         "options": {
          "inject": true,
          "minify": true,
          "depCache": true,
          "rev": false
       }
      },
      "dist/aurelia": {
        "includes": [
          "aurelia-framework",
          "aurelia-bootstrapper",
         "aurelia-fetch-client",
   }
 };

With outputPath in the bundle config the resulting files will be:

Injection config will be calculated relative to dist as usual.

RomkeVdMeulen commented 7 years ago

Finally got around to trying this out. It works perfectly. Thanks for this!