Skip to content
This repository has been archived by the owner on Oct 9, 2020. It is now read-only.

Automate build gulp workflow with systemjs-builder #23

Closed
martinmicunda opened this issue Nov 16, 2014 · 11 comments
Closed

Automate build gulp workflow with systemjs-builder #23

martinmicunda opened this issue Nov 16, 2014 · 11 comments

Comments

@martinmicunda
Copy link

Hi,

I am trying to automated my workflow to build bundle with gulp but I am getting 2 errors and I wasn't sure where to post this question so I have opened new issue.

Issue 1:
As I mentioned early I try automated my workflow with gulp that use systemjs-builder for bundle task. I don't want to manually add maps, version etc. to builder.build() (see gulpfile.js below) as I think this configuration doesn't belong to gulpfile.js so I put them into jspm.conf.js (systemjs doing the same thing). The problem is that I was not able to figure out how to load this file with System.config in jspm.conf.js (see what I would like to use) because when I require('./jspm.conf.js') in gulpfile I am getting ReferenceError: System is not defined which make sense as System is part of systemjs so I export config stuff (see what I am using now) and this works fine where I run my gulp task however if I run jspm install it always overwrite jspm.conf.js and add System.config which I can't load into Builder.build(). Also if I make any manual changes in jspm.conf.js and then I run jspm install my changes are overwrite and this can possible cause an issue in future when somebody else try clone my repo and run jspm install then my manual changes will be gone and overwrite.

Basically what I am trying to do is get running gulp bundle task with systemjs-builder and keep to config systemjs data out of the gulpfile.js in jspm.conf.js. I am not sure if that make sense for you :)

gulpfile.js

gulp.task('scripts', 'Compile JS files into the app.js', function (cb) {
    var config = require('./jspm.conf.js');
    var builder = require('systemjs-builder');

    builder.build('src/app/bootstrap',
        config,
        paths.tmp.scripts + 'app.js')
            .then(cb)
            .catch(function(ex) {
                cb(new Error(ex));
            });
});

jspm.conf.js
what I am using now

(function() {
  var config = {
    "paths": {
      "*": "*.js",
      "npm:*": "jspm_packages/npm/*.js",
      "github:*": "jspm_packages/github/*.js"
    },
    // any map config
    map: {
      "angular": "github:angular/bower-angular@^1.3.2",
      "angular-animate": "github:angular/bower-angular-animate@^1.3.2",
      "github:angular/bower-angular-animate@1.3.2": {
        "angular": "github:angular/bower-angular@^1.3.2"
      }
    },
    "versions": {
      "github:angular/bower-angular": "1.3.2",
      "github:angular/bower-angular-animate": "1.3.2"
    }
  };

  module.exports = config;
})();

what I would like to use

System.config({
  "paths": {
    "*": "*.js",
    "github:*": "jspm_packages/github/*.js"
  }
});

System.config({
  "map": {
    "angular": "github:angular/bower-angular@^1.3.2",
    "angular-animate": "github:angular/bower-angular-animate@^1.3.2",
    "github:angular/bower-angular-animate@1.3.2": {
      "angular": "github:angular/bower-angular@^1.3.2"
    }
  }
});

System.config({
  "versions": {
    "github:angular/bower-angular": "1.3.2",
    "github:angular/bower-angular-animate": "1.3.2"
  }
});

My project structure:

my-project/ 
  |- src/                 --> all source code files
  |  |- .tmp/
  |  |  |- scripts
  |  |  |  |- app.js        --> bundle file
  |  |- app/                 --> angularJS 
  |  |  |- bootstrap.js        --> main app file (bootsrap angular app)
  |  |  |- index.html
  |- jspm.config.js     
  |- gulpfile.js
  |- package.json

index.html

<script src="../../jspm_packages/traceur-runtime.src.js"></script>
<script src="../../jspm_packages/es6-module-loader.src.js"></script>
<script src="../../jspm_packages/system.src.js"></script>
 <script src=".tmp/scripts/app.js"></script>

</script>
   System.import('src/app/bootstrap').then(function(m) {
     console.log(m);
   }, console.error.bind(console));
</script>

package.json

.....
all classic npm package stuff and at the end jspm
...
  "jspm": {
    "name": "angular-seed",
    "configFile": "jspm.conf.js",
    "dependencies": {
      "angular": "^1.3.2",
      "angular-animate": "^1.3.2"
    }
  }

issue 2:
I am getting below error when I am importing angular-animate . If I comment out import 'angular-animate' then angular is loading without any problem (I tried debug the issue but I couldn't figure out that)

Note: angular-animate had dependency on angular as you can see in jspm.conf.js

Error in browser console:

Uncaught SyntaxError: Unexpected token <
Error evaluating http://localhost:8000/angular.js          es6-module-loader.src.js:1141

src/app/bootstrap.js

import 'angular';
import 'angular-animate';       ---> this is throwing error

angular.element(document).ready(function () {
    angular.bootstrap(document, ['app'], {
        //strictDi: true
    });
});
@martinmicunda
Copy link
Author

I have actually fixed the issue 2 by adding <script src="../../jspm.conf.js"></script> into index.html.

@guybedford
Copy link
Member

Glad to hear you've fixed the second issue.

For the first issue, I've created an issue at #24. Once this is landed you'll be able to do:

var builder = require('systemjs-builder');
global.System = builder.loader;
require('./jspm.conf');
builder.build('app', null, 'out.js');

@guybedford
Copy link
Member

I've added this feature in https://github.com/systemjs/builder#loading-a-separate-config-file. Release coming shortly, let me know if that helps.

@martinmicunda
Copy link
Author

@guybedford Yeah that's working fine now.. :) But I have found another issue :( I am using gulp watch to re-run scripts task each time I make any change in js files and I can see the scripts task is running when I make a change in js files however the builder.build doesn't compile any code (the compilation is running only once when I run scripts task first time) so I have added builder.reset() to reset the loader each time I re-run scripts task (my hope was this could fix the problem) but I am getting follow error:

Issue 1
Error:

[11:00:07] 'scripts' errored after 87 ms
[11:00:07] Error: Error: ENOENT, open '/Users/martinmicunda/projects/employee-scheduling/ui/angular.js'

gulp scripts taks

gulp.task('scripts', 'Compile JS files into the app.js', ['build-init'], function (cb) {
    var builder = require('systemjs-builder');
    builder.reset(); --> this cause error after each re-run
    builder.loadConfig('./src/jspm.conf.js');

    builder.build('src/app/app',
        paths.tmp.scripts + 'app.js')
        .then(function() {
            console.log('es6 build');
            return cb();
        })
        .catch(function(ex) {
            cb(new Error(ex));
        });
});

Issue 2
The issue is not major but builder crash when build directory does not exist yet. I have workaround for it at the minute but this could be implemented in builder itself. Below task runs before scripts task to make sure build directory exist.

gulp.task('build-init', function (cb) {
    // systemjs-builder crashes, when build directory does not exist yet
    // so we will create it if needed
    fs.mkdir(paths.tmp.scripts, function (error) {
        if (error && error.code !== 'EEXIST') {return cb(error);}
        cb();
    });
});

@guybedford
Copy link
Member

It sounds like the configuration is not being properly sent in the build loader after running reset? It may be worth debugging if the path is not being normalized properly, and looking into if the correct map / paths config is present in the builder loader (inspecting builder.loader.map / builder.loader.paths after the builder.loadConfig call).

I've added directory creation in 0f065cf.

@martinmicunda
Copy link
Author

@guybedford I had a quick look at this issue and I tried debug loader.paths but I have problem to understand how this actually work. When I put breakpoint in global.System = curSystem; (see systemjs-builder code below) line I can see paths from jspm.conf.js are merge/overwrite to loader.path after require(path.resolve(..)) is executed however this is not happening when gulp scripts is running second time and it seems require(path.resolve(..)) doesn't merge/overwrite to loader.path.

systemjs-builder code

exports.loadConfig = function(configFile) {
    var curSystem = global.System;
    global.System = loader;
    require(path.resolve(process.cwd(), configFile)); --> this is resolved only once
    global.System = curSystem;
}

@guybedford
Copy link
Member

@martinmicunda that clarifies great - I've released a 0.3.1 with an updated loadConfig that works repeatedly now.

@guybedford
Copy link
Member

See https://github.com/systemjs/builder#loading-a-separate-config-file for the updated documentation.

@martinmicunda
Copy link
Author

@guybedford great I have test that and it works now.. thanks a lot! :)

I have find one more thing but I am not sure if this is issue.. supposed follow project structure:

my-project/ 
  |- src/    
  |  |- jspm_packages/              
  |  |- app/                  
  |  |  |- app.js         
  |  |  |- jspm.config.js   
  |  |  |- index.html
  |- gulpfile.js
  |- package.json 

When I run jspm install the jspm_packages are installed under src/ directory because that's where I keep my jspm.config.js file (I have specified that in the package.json file). However when I am using builder it will throw error because is expecting jspm_packages to be at root level (my gulpfile.js is in root level) so shouldn't builder assume when I am passing './src/jspm.conf.js' that packages are installed in src/ directory and not in the root directory?

gulp.task('scripts', 'Compile JS files into the app.js', function (cb) {
    var builder = require('systemjs-builder');
    builder.reset();

    builder.loadConfig('./src/jspm.conf.js')
        .then(function() {
            builder.build('src/app/app', paths.tmp.scripts + 'app.js');
        });
});

@guybedford
Copy link
Member

Yes you need to set the baseURL for builder to reflect the baseURL:

builder.loadConfig('./src/jspm.conf.js')
.then(function() {
  builder.loader.baseURL = path.resolve('./src/');
  return builder.build('app/app')
})

etc. This is done automatically when running bundling through jspm (https://github.com/jspm/jspm-cli/blob/master/lib/bundle.js#L84).

@martinmicunda
Copy link
Author

thanks

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants