Giter VIP home page Giter VIP logo

jspm-dev-builder's Introduction

jspm-dev-builder

A small module for running jspm development builds.

Note: if you're running jspm 0.17-beta12 or higher, this feature is now built in! See this GitHub issue for more information.

Motivations

When you're working on small applications, one of the best features of jspm is that you don't need to run any form of watch task. jspm loads and transpiles everything in the browser, and in development this workflow works really well. However, when your app reaches a certain size the overhead of running everything in the browser leads to your app taking multiple seconds to refresh.

At this point, you can switch to bundling your application whenever you save a file to generate a large, unminified bundle file which you can give to your browser. This is made possible thanks to recent additions to jspm that enable builds to make use of a build cache. On an application with ~800 modules, we've seen the initial jspm build hit 6-7 seconds, but after a file change we see the app rebuild in ~0.5 seconds.

Usage

var DevBuilder = require('jspm-dev-builder');

var appDevBuilder = new DevBuilder({
  jspm: require('jspm'), // so you can use your local version of jspm
  expression: path.join('app', 'bootstrap.js'), // path to your app's entry point
  outLoc: path.join('client', 'app-bundle.js'), // where you want the output file
  logPrefix: 'jspm-app', // put at the beginning of log messages from dev builder
  buildOptions: {
    sfx: false, // if the build should be self executing (please see note below on Self Executing Builds)
    // below options are passed straight through to the builder
    // the values shown are the defaults
    minify: false,
    mangle: false,
    sourceMaps: false,
    lowResSourceMaps: false,
  }
});

You can then call appDevBuilder.build() to generate a new build. If a file has changed and you need to rebuild, call appDevBuilder.build('file-that-changed.js'). This will cause the builder to invalidate the cache for the file that changed, and hence when a new build is generated it will have the new version of that file within it.

If you don't pass DevBuilder a version of jspm to use, it will use its own version, which is currently set at 0.16.12. Note that in order for the cache invalidation to work as expected, you must be using jspm 0.16.12 or newer. If you are stuck on an older version, you'll have to override DevBuilder.prototype.removeFromTrace.

Self Executing Builds

There is currently a bug in jspm that causes cache invalidation to break with self executing builds. Issue #9 is tracking this problem. Until then this plugin will not work well with self executing builds; you are advised to only use this with regular builds.

Sample Output

Below is a CLI output from a watch task that is using jspm-dev-builder to generate a bundle.

jspm-app jspm build starting app/bootstrap.js
jspm-app jspm build finished 4911
Watching files!
File changed: app/routes/home/index/home-index.controller.js
jspm-app Deleting app-compiled/routes/home/index/home-index.controller.js from trace cache
jspm-app jspm build starting app/bootstrap.js
jspm-app jspm build finished 429

Changelog

0.4.0

  • add logging of jspm.version
  • update to latest stable jspm (0.16.32)

0.3.2

  • add message about SFX cache invalidation being buggy that links to #9.

0.3.1

  • updated deprecated calls to the builder. Added more messaging during cache invalidation. More examples - for SFX as well.

0.3.0

  • fixed the build function creating a new instance each time, and hence ignoring the cache - thanks @OrKoN for the PR

0.2.0

  • renamed inLoc to expression
  • added buildOptions which are passed through to SystemJS-builder
  • added buildOptions.sfx to turn on self executing bundling
  • upgraded to jspm 0.16.12, and use the new SystemJS-Builder cache invalidation

0.1.0

  • initial release

jspm-dev-builder's People

Contributors

ebpa avatar jackfranklin avatar karlpurk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

jspm-dev-builder's Issues

Invalidating file with syntax error breaks further invalidations for that file

You use incremental build
The initial build succeed and then change file to have a syntax error,
the file is sent to builder.build(filepath)
the build fails with error like:

jspm build jspm build error file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx: Unterminated string constant (55:0)
  53 |     }
  54 | }
> 55 | '
     | ^
  56 | export default Root;
  57 |  Error on translate for js/***/Mobile/Components/Root.jsx at file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx
    Loading js/***/Mobile/main.js
    SyntaxError: file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx: Unterminated string constant (55:0)
  53 |     }
  54 | }
> 55 | '
     | ^
  56 | export default Root;
  57 | 
    at Parser.pp.raise (evalmachine.<anonymous>:63062:13)

You fix the syntax error, and the watcher send the file to builder.build(filepath) again
But then you get that error:

jspm build jspm invalidation error Nothing has been invalidated for js/***/Mobile/Components/Root.jsx. It's likely that the module does not exist. If the module is loaded using a plugin, you need to append ! to its name in order to invalidate it properly
jspm build jspm build starting js/***/Mobile/main.js
jspm build Building non-SFX bundle
jspm build jspm build error file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx: Unterminated string constant (55:0)
  53 |     }
  54 | }
> 55 | '
     | ^
  56 | export default Root;
  57 |  Error on translate for js/***/Mobile/Components/Root.jsx at file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx
  Loading js/***/Mobile/main.js
  SyntaxError: file:///Users/bnaya/dev/***/mobile2/src/js/***/Mobile/Components/Root.jsx: Unterminated string constant (55:0)
  53 |     }
  54 | }
> 55 | '
     | ^
  56 | export default Root;
  57 | 
    at Parser.pp.raise (evalmachine.<anonymous>:63062:13)
...

It's like systemjs/builder caches the broken content of the file, and the builder.invalidate fails like its not in the cache.

And need to restart you watch task to make it work again.

JSX: Build does not include dependencies of a changed module in bundle

I have the following gulpfile:

var gulp = require("gulp"),
    DevBuilder = require('jspm-dev-builder'),
    jspm = require("jspm"),
    path = require("path");

gulp.task("watch", function() {
    var appDevBuilder = new DevBuilder({
        jspm: jspm,
        expression: "scripts/bootstrap.js",
        outLoc: "public/bundle.js"
    });

    appDevBuilder.build();

    gulp.watch("public/scripts/**/*.{js,jsx}").on("change", function(file) {
        var changedPath = path.relative(path.join(__dirname, "public"), file.path);
        if (changedPath.endsWith(".jsx"))
            changedPath += "!";

        appDevBuilder.build(changedPath);
    });
});

Bootstrap is simply: import "./application.jsx!"

Application.jsx imports react, react-dom, lodash, and component.jsx!. Component.jsx simply imports react and exports a component.

Here's what happens:

  • The first build works just fine. I get an entire bundle of bootstrap, application, component, react, react-dom, etc.
  • If I edit component.jsx OR bootstrap.js, it rebuilds correctly.
  • If I edit application.jsx - the rendered bundle does NOT include anything BUT application.jsx and bootstrap.js. React, react-dom, component, etc, are all no longer included.

Basically, it seems that if I edit a module that is the first in the hierarchy to import another module, that imported module is no longer included in any further bundles. This only seems to happen with jsx files, not with regular js files. It also appears that the extra runtime and polyfills are also ignored.

I'm using the following JSPM modules:

      "jsx": "npm:jspm-loader-jsx@^0.0.7",
      "lodash": "npm:lodash@^3.10.1",
      "react": "npm:react@^0.14.3",
      "react-dom": "npm:react-dom@^0.14.3"
      "babel": "npm:babel-core@^5.8.24",
      "babel-runtime": "npm:babel-runtime@^5.8.24",
      "core-js": "npm:core-js@^1.1.4"

And the following NPM modules:

    "jspm": "^0.16.15",
    "jspm-dev-builder": "^0.3.2"

I'm asking here because I wonder if anyone else has gotten around this issue with this tool. I believe this is: A) me using DevBuilder incorrectly, B) a bug in JSPM, or C) a bug in jspm-loader-jsx.

Honestly, this tool legitimizes the use of JSPM as a package loader for us stuck on HTTP/1 (and should probably be built into JSPM itself), and it'll be very sad if I can't get around this issue.

Self Executing Build Problems

When I watch the file tree and rebuild (while invalidating files) I get really strange behavior. I get a file not found error for loading a JS file that doesn't (and shouldn't exist).

Example:

jspm-app Invalidated /home/blittle/dev/sme-frontend/src/organizer/index.js from cache
jspm-app jspm build starting src/main.js
jspm-app Building SFX bundle
jspm-app jspm build error ENOENT: no such file or directory, open '/home/blittle/dev/sme-frontend/98.js' Error on fetch for 98.js at file:///home/blittle/dev/sme-frontend/98.js
        Loading src/main.js
        Loading src/root.component.js
        Loading src/organizer/index.js
        Error: ENOENT: no such file or directory, open '/home/blittle/dev/sme-frontend/98.js'
    at Error (native)

Notice the loading of 98.js. I have no idea where that is coming from, though it is some how tied to the file that is being invalidated. If Invalidate a different file, I get a different number. Though when I come back to index.js it is always 98.

The number jspm is trying to load also seems associated with the depth in the dependency tree. If I invalidate my main app entry point main.js then the error is for loading 3.js whereas deeper dependencies are larger numbers.

I have been trying to go through systemjs-builder to understand more clearly what is going on. Any ideas?

Problems for invalidating files. Cache is empty.

Hi all!

I have been making some tests with this project and I couldn't make it work for invalidating a single file. Looks like my builder.cache.trace is an empty object so nothing is being cached.

I have been reading the docs but it doesn't say anything about this. I suppose that JSPM manages the cache by itself and nothing should be configured from our side, doesn't it?

I'm using [email protected]

Any help would be really appreciated! :)

Many thanks!

Source maps support?

The project is great! But I wonder if you use it w/o source map support? Is it possible to have source maps for the bundle?

Every other build w/ Babel breaks

When using jspm-dev-builder to enable partial rebuilds of an app, having configured jspm to transpile with Babel, every other built bundle seems to contain non-canonicalized dependencies in the file that was changed. Performing another partial build, again first invalidating that same file, corrects the issue, but the bundle after that breaks it again etc.

This is what the bundle looks like, correct on the left and broken on the right:

A repro test can be found here https://gist.github.com/tjclement/7d6e606b2ba4411ced51

This is caused by a bug in systemjs/builder, which is tracked at systemjs/builder#448

Create a CLI Tool

So people don't have to implement the CLI tool themselves.

It should allow the user to run a command which:

  • builds their app with jspm
  • watches for files changing (can take a glob, or has a default of **/*.js, excluding some sensible defaults), and rerun the app
  • (potentially) hooks into a live reload thing?

running devBuilder.build results with Run jspm init first

Trying to run devBuilder.build from gulp and results with 'Package.json file has not been initialized by jspm before. Run jspm init first.'

is it possible to execute build from a location other than the one package.json and config.js resides?

Thanks a lot!

Build stops working on errors during the build process

To track another problem with errors in plugins/build process.

Steps to reproduce:

  1. start a non-sfx build
  2. put some bad handlebars to main.hbs (e.g. {{#test}}) and save
  3. a build is attempted and an error is printed to the console (e.g. Expecting 'OPEN_INVERSE_CHAIN', 'INVERSE', 'OPEN_ENDBLOCK', got 'EOF')
  4. remove the bad handlebars piece and save

Expected: the build is successful again.
Actual: the build fails because of the bad handlebars that is not present in the file anymore

Thoughts

Couple of thoughts:

  1. inLoc would be better named as expression. jspm defines a bundle expression as something like main or main - jquery (it can contain arithmetic). https://github.com/jspm/jspm-cli/blob/84fd8cff30ae538970b90c143ec8a7d99f6bf725/lib/bundle.js#L75
  2. We should add the ability to pass bundle options (minify, no mangle, source map, source map contents…)
  3. We should add the ability to choose between bundle and bundle SFX (builder.buildStatic)
  4. I'm not sure about the implementation of removeFromTrace (
    var traceKeys = Object.keys(sharedCache.trace);
    traceKeys.filter(function(key) {
    return key.indexOf(filename) > - 1;
    }).forEach(function(key) {
    this.logInfo('Deleting', chalk.blue(key), 'from trace cache');
    delete sharedCache.trace[key];
    }, this);
    ). If the filename passed in is absolute (as is often for watch tasks), it won't match. Perhaps this function should expect a moduleId which it can match exactly in sharedCache.trace. Then, it is up to the consumer to map file paths to SystemJS module ID in the watch event listener. Alternatively it could receive the absolute path, make it relative to the jspm base URL, and then run it through System.normalize to get the module ID.

For now I have just copied the code into my project for direct use. What do you think?

/* eslint-env node */
import gulp from 'gulp';
import watch from 'gulp-watch';
import jspm from 'jspm';
import path from 'path';

let builderCache = {};

const removeFromTrace = (moduleId) => delete builderCache.trace[moduleId];

const moduleExpression = 'main';
const writeFileName = `${__dirname}/public/js/main-bundle.js`;

const build = (changedModuleId) => {
    const builder = new jspm.Builder();

    if (changedModuleId) {
        removeFromTrace(changedModuleId);
    }

    builder.setCache(builderCache);

    const buildStart = Date.now();
    return builder.buildStatic(moduleExpression, writeFileName)
        .then(() => {
            builderCache = builder.getCache();

            const buildEnd = Date.now();
            console.log(`bundle time: ${buildEnd - buildStart}`);
        });
};

gulp.task('build', () => build());

gulp.task('watch', ['build'], () => {
    const baseURL = new jspm.Builder().loader.baseURL.replace('file://', '');
    return watch(`${baseURL}/**/*.js`, (vinyl) => {
        // TODO: Map to module ID. How?
        const moduleId = path.relative(baseURL, vinyl.path);
        console.log(`changed: ${moduleId}`);
        build(moduleId);
    });
});

Callback

Thanks for the module, it works like charm.

Is there a way to provide a callback for build method for better gulp integration?

Doesn't change subsequent output?

When called from the gulp task the first time, all changes are reflected. However, once chokidar emits a file changed and I pass it to appDevBuilder, it says it's invalidating it from cache and I get a "jspm build finished xxx" but the output isn't actually changed when I inspect the file.

I'm using almost the same config verbatim, except my input & output is nested a few folders deep -- but like I said, chokidar finds and passes the changed file file. Is there some special consideration I'm missing, because I thought it would be as simple as passing the path to the instantiated jspm-dev-builder object

jspm 0.16.12

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.