JSPM

fuse-box

1.2.97
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 5753
  • Score
    100M100P100Q142822F
  • License ISC

Fuse-Box a bundler just does it right

Package Exports

  • fuse-box
  • fuse-box/dist/commonjs/BundleSource

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (fuse-box) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Build Status

FuseBox

The library is under heavy development. We are getting there.

Introduction

FusBox is a bundler/module loader that combines the power of webpack and JSPM. It is blazing fast (it takes 50-100ms to re-bundle) which makes it extremely convenient to develop.

Say no to painful "get started", say no to huge configs. Fuse it all!

angular2-example 50ms to build!

react-example 50ms to build

Why fusebox?

Bundle anything without an extra effort

You have an npm library in mind? You can bundle it without any extra configuration. babel-core with all plugins? No problem, fusebox takes care of everything you need.

All node modules (at least the most critical ones) will be bundled for browser (Buffer, path e.t.c) So you don't need to stress about whether you bundle will work in the browser. IT WILL.

It is blazing fast

Fusebox is super fast. 50ms for a regular project, 100ms for a big project to re-bundle. It applies aggressive but responsible module caching, which makes it fly.

Check this benchmark:

1200 files to require once

FuseBox 0.234s
Webpack 1.376s

1000 files to require / 10 times

FuseBox 2.257s
Webpack 13.591s

1000 Webpack FuseBox

Built-in typescript support.

FuseBox is written in typescript, so I could not just proceed without a seamless typescript intergration. In fact, you don't need to configure anything! Just point it to a typescript file, and FuseBox will do the rest.

fuseBox.bundle(">index.ts");

Arithmetic instructions

With arithmetic instructions you can explicitly define which files go to the bundle, which files skip external dependencies.

For example.

fuseBox.bundle(">index.ts [lib/**/*.ts]");

In this case, you will get everything that is required in the index, as well as everything that lies under lib/ folder with one condition - any external libraries will be ignored.

> index.js [**/*.js] - Bundle everything without dependencies, and execute index.js

[**/*.js] - Bundle everything without dependencies

**/*.js - Bundle everything with dependencies

**/*.js -path - Bundle everything with dependencies except for path

Extensive plugins

Have an idea in mind? Just develop a plugin, it's extremely easy to make one. Besides, we have a few plugins, that will help you get started. Want to develop one? Read-up here

How FuseBox works?!

The idea of FuseBox was born, when started struggling with webpack. It is slow, and it did not deliver required functionality. On another hand, jspm did what I wanted, but still it was not something I would go for. So I decided to combine both and create my own version that has a power of both bundlers combined.

Static analysis (acorn)

Behind the scenes, fusebox uses acorn to make static analisys on your code, extracting require statements and es6 imports. So, as long as it is a valid javascript es5 or es6, you will get your code bundled with no plugins required.

Aggressive npm caching

FuseBox uses agressive caching for your modules. It knows when a file is modified. It knows exactly which version of npm lib you are using, as well as explicit requires like require('lodash/each')

Nodejs ecosystem and lifecycle in the browser

FuseBox appends a very tiny API footer that makes magic happen. The library does not modify your source code, it creates 100% compatible commonjs wrapper

(function (exports, require, module, __filename, __dirname) {
// Your module code actually lives in here
});

It behaves exactly the same in browser and on server, including circular dependencies resolution. Surely, it works in node as well.

Fuse it all

Anything

The concept of FuseBox is simple. Bundle anything with minimum configuration. You can point your files to a typescript file or to a javascript file. It will understand es6 import statements as well. You need, however, use BabelPlugin to transpile it.

Typescript

Typescript does not require any external plugin or configuration. Make sure you have typescript compiler installed

npm install typescript --save-dev

Now let's define a simple configuration

FuseBox.init({
    homeDir: "src/",
    sourceMap: {
         bundleReference: "./sourcemaps.js.map",
         outFile: "sourcemaps.js.map",
    },
    outFile: "./out.js"
}).bundle(">index.ts");

FuseBox automatically switches to a typescript mode and compiles your files. Place tsconfig.json in your homeDir. It will be loaded automatically. For your own convenience add Typescript helpers plugin.

Export from bundle

You can easily export any library from your bundle to window/module.exports accordingly. Simply add this property:

globals: { default: "myLib", "wires-reactive": "Reactive" }

Whereas key is the name of a package and value is an alias that groups exports. "default" is your current project. Please, note, that in order to expose your default package, a bundle must have an entry point.

Full example:

FuseBox.init({
    homeDir: "src/",
    globals: { default: "myLib"},
    outFile: "./out.js"
}).bundle(">index.js");

Point to the root

You can use ~ symbol to point to your project's path in order to solve ../../../../../utils mess.

// es5
require("~/lib/utils")
// es6
import * as utils from "~/lib/utils";

Loader API

FuseBox bundle works in both environments. Essentially, it does not matter where you run. FuseBox will persist itself in browser window, or nodejs globals.

Every bundle contains a 3k footer with FuseBox API, It is less than 3KB minified (1,4KB gzipped).

Import

Import is 100% compatible with commonjs specification. You can require folders, skip file extensions (fusebox will guess it).

FuseBox.import("./foo/bar");

Requre external packages will work as well

FuseBox.import("fs");

Please, not, that some libraries like "fs" are faked on browser. Meaning that it won't spit an error, but won't work as expected on server for known reasons. Nodejs environment, however, will get authentic "fs" module. (Concerns http, net, tty e.t.c )

Exists

You check wether a module (file) exists in scope.

FuseBox.exists("./index")

Event binding

It is possible to intercept require statements. Use "on" method.

FuseBox.on("before-import", (exports, require, module, __filename, __dirname, pkg) => {                
});

FuseBox.on("after-import", (exports, require, module, __filename, __dirname, pkg) => {                
});

2 events are available at the moment "before-import" and "after-import", Provides commonjs environment (+ package name) in the callback. "require" function is "homie" and respects file location.

Dynamic

Like SystemJS FuseBox provides a hacky way of creating a dynamic module from a string. After it has been initialized it shared 100% the same environment and behaves accordingly.

FuseBox.dynamic("stuff/boo.js", "module.exports = {hello : 'dynamic'}; require('./foo')")

A bundle can reference "stuff/boo.js" once a dynamic module was initialized.

FuseBox events

It is possible to intercept require statements. You can catch "before-import" and "after-import" events like so:

FuseBox.on("before-import", (exports, require, module, __filename, __dirname, pkg) => {                
});

FuseBox.on("after-import", (exports, require, module, __filename, __dirname, pkg) => {                
});

It is not recommended, however, if you want to play god, you can use that functionality.

Built-in plugins

Fusebox contains premade plugins, that should help you to get started.

CSS Plugin

It's very to start working css files You have 2 options, you either bundle the contents or serve files. A decision can be made at build time.

For example:

plugins: [
    fsbx.CSSPlugin({
        minify: true
    })
]

In this case, all css files will be bundled.

But if you define "serve" option with a callback, all files will be filtered through it. A callback is expected to return a string with a browser path. If you return "undefined" or NOT a string, that file will be bundled as if no option was specified.

All css files will be served by server.

plugins: [
    fsbx.CSSPlugin({
        minify: true,
        serve: path => `./${path}`
    })
]

All files will be served except for "styles.css" (contents will be included in the bundle)

plugins: [
    fsbx.CSSPlugin({
        minify: true,
        serve: path => path === "styles.css` ? 0 : ./${path}`
    })
]

HTML Plugin

Add HTMLPlugin like so:

plugins: [
  fsbx.HTMLPlugin({ useDefault: false })
]

Toggle useDefault to make html files export strings as default property. For example with useDefault: true you will be able to import HTML files like so :

import tpl from "~/views/file.html"

Babel plugin

You can use babel plugin to transpile your code. Make sure you have babel-core installed

npm install babel-core babel-preset-es2015 babel-plugin-transform-react-jsx

For example. to transpile JSX, you can use this configuration.

 plugins: [
    fsbx.BabelPlugin({
        test: /\.jsx$/,
        config: {
            sourceMaps: true,
            presets: ["es2015"],
            plugins: [
                ["transform-react-jsx"]
            ]
        }
    })
]

Note, that if you want to have sourcemaps in place, set sourceMaps to true. Read sourcemaps section for better understanding how sourcemaps are defined.

Typescript helpers

A very handy plugin, adds required typescript functions to the bundle. Please, note, that it adds only the ones that are actually used. So you won't be seeing an unnecessary code.

Please, check this list

Available helpers:

Name Description
__assign Generic typescript helper
__awaiter Generic typescript helper
__decorator Generic typescript helper + additional fusebox meta data patched
__extends Generic typescript helper
__generator Generic typescript helper
__param Generic typescript helper

If you spot an error or a missing helper, please, submit an issue, or a pull request. If you feel impatient enough, you can always create your own plugin, based on this class code

Using the plugin

Simple add TypeScriptHelpers to your plugin list. No further configuration required. FuseBox will take care of everything else. To avoid unnecessary AST (which is heavy) this plugin does a simple RegExp, and tests for declarations. It is absolutely safe, and your code is not modified in any way.

const fsbx = require("fuse-box");
let fuseBox = fsbx.FuseBox.init({
    homeDir: "test/fixtures/cases/ts",
    outFile: "./out.js",
    plugins: [fsbx.TypeScriptHelpers()]
});

Extended metadata properties

You can have access to the entire environment of a file, using reflect-metadata. Make sure you have it installed first

npm install reflect-metadata

Than, include it in your entry point

import "reflect-metadata";

Now, you can access "commonjs" variables via fusebox metadata property

export function testDecorator() {
    return function (target, key: string, descriptor: PropertyDescriptor) {
        Reflect.getMetadata("fusebox:__filename", target, key);
        Reflect.getMetadata("fusebox:__dirname", target, key);
        Reflect.getMetadata("fusebox:require", target, key); // Local "require" function
        Reflect.getMetadata("fusebox:module", target, key);
        Reflect.getMetadata("fusebox:exports", target, key);
    }
}

Sourcemaps

Sourcemaps in FuseBox are enabled by adding this property to a fusebox init configuration

sourceMap: {
  bundleReference: "sourcemaps.js.map",
  outFile: "sourcemaps.js.map",
}

bundleReference speaks for itself. This line will be added to the bundle. For example //# sourceMappingURL=./sourcemaps.js.map. If your client is not able to read them, make sure that the path is reachable.

Sourcemaps currently work with typescript and BabelPlugin

Plugin API

Let's take a look a plugin's interface first

interface Plugin {
    test?: RegExp;
    dependencies?: string[];
    init: { (context: WorkFlowContext) };
    transform: { (file: File) };
    bundleStart?(context: WorkFlowContext);
    bundleEnd?(context: WorkFlowContext);
}

test [RegExp]

Defining test will filter files into your plugin. For example \.js$