fuse-box
Version:
Fuse-Box a bundler that does it right
679 lines (487 loc) • 16.5 kB
Markdown
# Configuration
The concept of FuseBox is simple. Bundle anything for frontend and server without a headache. Simply put, you can copy paste a simple config down below and bundle some heavy module like `babel-core` or `babel-generator`. But let's get started and break down all available options in fusebox.
## Initialisation
Initialise a fuse-box instance like so.
```js
FuseBox.init({ /* you config is here */ })
```
## Home directory
That's your _source_ folder. FuseBox locks your project to it. FuseBox will resolve it relatively your `fuse.js` file location
```js
FuseBox.init({
homeDir: "src/",
})
```
files:
node_modules
placeholder.js
stuff
src
index.ts
fuse.js
In the example above your `homeDir` will be pointing to `stuff/src` next to `fuse.js` file.
note: it's not recommended using absolute paths. It reduces readability
## Output
Output is a string which is used by FuseBox to determine where and how to place your bundles in the file system.
```js
FuseBox.init({
homeDir: "src",
output: "build/$name.js",
})
```
There are few macros available.
| Name | Description |
| ------------- | ------------- |
| $name | The name of your bundle |
| $hash | Applying hash when available |
`$hash` is used when the hash option is set, otherwise it will be removed. FuseBox will create folders automatically, so you don't need to worry if a folder is present. FuseBox will also tolerate an absense of `$name` macro, converting it internally into a template
For example this:
```js
output: "build/out.js"
```
Will be converted accordingly to:
```js
output: "build/$name.js"
```
However it is strongly recommended to use `$name` in your output template, as `out.js` will be ignored
## Cache
You can turn off caching if you like. By default caching is on. FuseBox will create a folder `.fusebox` in your project path, and store related files. Don't forget to add it to .gitignore.
note: If things go wrong or things are not updating, delete the `.fusebox` folder to force clear the cache.
```js
const fuse = FuseBox.init({
homeDir: "src",
output: "build/$name.js",
cache: true
})
```
Alternatively, you can disable cache by using chainable API
```js
fuse.bundle("app")
.cache(false)
.instructions("> index.ts")
```
## Debug and Log
Additional logging and debugging can be enabled, but keep in mind they can reduce performance.
```js
const fuse = FuseBox.init({
homeDir: "src",
output: "build/$name.js",
log: true,
debug: true
})
```
## Custom modules folder
You probably would want to test a package some day, or just have an abstraction on top of your code. For that, you can use `modulesFolder` property. It behaves exactly the same like another npm module, just in a custom folder.
```js
FuseBox.init({
modulesFolder: "modules",
})
```
You local `npm` will have the highest priority. In essence, you can override fusebox's [path](https://github.com/fuse-box/fuse-box/blob/master/modules/path/index.js) of [fs](https://github.com/fuse-box/fuse-box/blob/master/modules/fs/index.js) module if you like. Customize you packages in your own manner!
files:
modules
foo
index.js
src
index.ts
You don't need to create `package.json` - `index.js` will work just fine. It will be [cached](#cache) like any other npm module with version `0.0.0`, so remember to toggle cache property in the config
## tsConfig
A path to typescript configuration `tsconfig` can be overridden like so:
```js
FuseBox.init({
tsConfig : "src/myconfig.json"
})
```
Or using the chain API
```js
fuse
.bundle("app")
.tsConfig("src/myconfig.json")
```
## Package Name
Your default package name is `default`. You don't need to change it if you are not planning on having isolated bundles.
Any bundle added as a script tag will share the `default` package, keep that in mind. If you want to release a package (say to NPM), you probably would want set a different name (to avoid scope collision)
It's imperative to have a __unique name__ (matching an npm package) when publishing a bundle to NPM.
```js
FuseBox.init({
package: "mySuperLib",
})
```
If you want to have an entry point (main) file, define it like so:
```js
FuseBox.init({
package:{
name: "mySuperLib",
main: "index.ts",
},
})
```
note: If you don't want to have your package execute on load, make sure your instruction does not have `>` in it.
Here is an example how make a package:
```js
const fuse = FuseBox.init({
homeDir: `src-package`,
outFile: `build/$name.js`,
package: {
name: "super-name",
entry: "index.ts",
},
});
fuse.bundle("app").instructions("index.ts")
```
## Global Variables
You can expose your package variables to `window` (in browsers) or `exports` (in Node).
```js
FuseBox.init({
// exposes window.mySuperLib
globals: { default: "mySuperLib" },
})
```
<!--Whereas key is the name of a package and value is an alias that groups exports. "default" is your current project.-->
Each key in the `globals` hash is the name of a package, and its value is an alias that groups exports. "default" is your current project.
You can also expose your package's exports to `window` or `exports`.
```js
// assuming mySuperLib exports a "handler" and "logger" property
FuseBox.init({
// exposes window.superHandler
globals: { "mySuperLib": { "handler": "superHandler"} },
// OR
// exposes window.handler and window.logger
globals: { "mySuperLib": "*" },
})
```
You can use the chainable API if you like:
```js
fuse.bundle("app").globals(/* configuration */)
```
note: In order to expose your package, a bundle must have a [package name](#package-name)
To see it in action, clone [this](https://github.com/fuse-box/fuse-box-globals-example) repository
```bash
git clone https://github.com/fuse-box/fuse-box-globals-example
npm install
node fuse
```
## Hash
Hashing is enabled by adding a `hash` property and setting it to `true`.
Make sure you checked the [output](#output) section.
```js
FuseBox.init({
hash : true
})
```
There are 2 ways to get to the generated file names
### Hashes and WebIndexPlugin
Use [WebIndexPlugin](/plugins/webindexplugin#webindexplugin) which will take care of everything. Generated files names will be in your script tags
```js
WebIndexPlugin({
title: "My awesome website",
})
```
### Hashes and bundles
You can retreive bundle names from a [producer](/page/bundle#producer) like so:
```js
fuse.run().then(producer => {
producer.bundles.forEach((bundle, name) => {
bundle.output.lastPrimaryOutput.filename
});
})
```
lastPrimaryOutput contains the following information
| Property | Description |
| ------------- | ------------- |
| `path` | Full path to the file |
| `hash` | Generated hash |
| `filename` | Filename |
## useJsNext
If this option is `true` FuseBox will take "json:next" or "module" properties from `package.json` if avaialable
```js
FuseBox.init({
useJsNext : true
})
```
Alternatively you can pass a array of strings telling FuseBox which modules should try for js:next
```js
FuseBox.init({
useJsNext : ["antd"]
})
```
## useTypescriptCompiler
You can transpile normal javascript with typescript compiler. All you need to do is toggle this flag
```js
FuseBox.init({
useTypescriptCompiler : true
})
```
And install typescript
```
npm install typescript --save-dev
```
## polyfillNonStandardDefaultUsage
Fixes non-standard import `default` whereas a package doesn't export one. For example:
```js
FuseBox.init({
useJsNext : ["react", "react-dom"],
polyfillNonStandardDefaultUsage : true
})
```
```js
import React from "react"
```
This functionality will not work in your project (people should stop relying on it, it's limited by design), but it's targeted to dependencies where `useJsNext` is interconnected.
it's strongly recommended NOT to use libraries that don't conform to javascript standards, like `react-router`, you may continue using it, but in this case don't toggle `useJsNext`
This option will polyfill every single file in a package, it won't affect much the size in Quantum, as it will be transpiled into:
```js
$fsx.r(122)(module.exports)
```
You may optionally choose packages to polyfill
```js
FuseBox.init({
useJsNext : ["react", "react-dom"],
polyfillNonStandardDefaultUsage : ["react", "react-dom"]
})
```
And as a reminder, a proper way of importing React is as follows:
```js
import * as React from "react"
```
## writeBundles
If you wish to write bundles yourself, set
```js
FuseBox.init({
writeBundles : false
})
```
Then in your `fuse.js` add the following code:
```js
fuse.run().then(producer => {
producer.bundles.forEach(bundle => {
console.log(bundle.context.output.lastPrimaryOutput);
});
})
```
`lastPrimaryOutput` will contain all the information you might require
## Sourcemaps
Project in FuseBox are enabled by setting the `sourceMaps` property and setting it to `true`:
```js
FuseBox.init({
sourceMaps: true
})
```
You can also provide an object to the `sourceMaps` property and then choose between project _and_ vendor sourcemaps:
```js
FuseBox.init({
sourceMaps: { project: true, vendor: true }
})
```
`sourceMaps` can also be configured via the chainable API:
```js
fuse.bundle("app").sourceMaps(true)
```
Sourcemaps currently work with typescript, BabelPlugin and SourceMapPlainJsPlugin
### Hosting source files
By default FuseBox inlines sources, that can be changed
```js
FuseBox.init({
sourceMaps: { inline: false }
})
```
If you want to serve your sourcemaps from the `homeDir`, you can use `sourceRoot`property to define the route mapped to your development server. The default value is `src/`
```js
FuseBox.init({
sourceMaps: { inline: false, sourceRoot : "/sources" }
})
```
note: Don't put a slash at the end with sourceRoot
## Standalone
By default FuseBox injects API in every bundle. That can be overridden by setting:
```
{ standalone : false }
```
Alternatively, you add the `!` symbol to the arithmetics, for example
```js
fuse.bundle("app").instructions("!>index.ts")
```
Load the API from the CDN:
```html
<script type="text/javascript" src="https://unpkg.com/fuse-box/dist/fusebox.min.js"></script>
```
## Plugins
`plugins` option expects an array of plugins
```js
FuseBox.init({
plugins:[
TypeScriptHelpers(),
JSONPlugin(),
[LESSPlugin(), CSSPlugin()],
],
})
```
Chaining is achieved by wrapping a list using array
```js
[LESSPlugin(), CSSPlugin()]
```
You can provided a RegEx or a simplified RegEx as a first element to override the initial match of a group:
```js
["less/*.less",LESSPlugin(), CSSPlugin()]
```
FuseBox tests each file running it through the plugin list. If it sees an array, it test for the first Plugin on the list test (which is `.scss` in our case.
```js
[".scss", SassPlugin(), CSSPlugin()] // simple and clean
[/\.scss$/, SassPlugin(), CSSPlugin()] // more verbose
```
By default only the first plugin to match a file will be applied to the file. E.g., in the following:
```js
new FuseBox({
plugins: [
ReplacePlugin({ __PRODUCTION__: isProduction }),
ReplacePlugin({ __SERVER__: false })
]
}).plugin(ReplacePlugin({ __IOS__: true }))
```
... only the `ReplacePlugin({ __PRODUCTION__: isProduction })` will be run on the files.
To make all of the plugins run, set `{ runAllMatchedPlugins: true }`.
## Target
At this moment target exists to switch to [electron](https://electron.atom.io/) mode
and [browser case](https://github.com/defunctzombie/package-browser-field-spec)
for electron:
```js
fuse.bundle("app").target("electron")
```
for browser (for example lib asap)
```js
fuse.bundle("app").target("browser")
```
We keep extending this functionality to provide more platform specific features.
### Example
```bash
git clone https://github.com/fuse-box/fuse-box-electron-seed.git
npm install
npm start
```
It's planned to introduce `browser` and `server` target that would affect the build. At this very moment, your builds are universal, that means that you can execute them on browser and on server accordingly.
## Simplified RegExp
FuseBox understands wildcards which are converted to RegExp
For example:
```js
plugins : [
["styles/*.css", CSSPlugin({group: "bundle.css"})] // will group files under "styles" folder
["components/*.css", CSSPlugin()] // will inline all styles that match components path
]
```
| Name | Description |
| ------------- | ------------- |
| `.css` | Matches all files ending with .css |
| `components/*.css` | Matches all css files in components folder |
| `components/**.css` | Matches all css files in components and under |
## Auto import
If you are into black magic, this API is for you.
```js
FuseBox.init({
autoImport: {
Inferno: "inferno",
},
})
```
Here, the key `Inferno` (uppercase) is a variable name, and `inferno` (lowercase) is the argument to a `require` statement.
Your code is being analysed for variable declarations. If you use the `Inferno` variable in your code in any way without declaring it,
FuseBox will inject the require statement `var Inferno = require("inferno")`.
Example:
```js
Inferno.doMagic()
```
Will result in:
```js
var Inferno = require("inferno");
Inferno.doMagic()
```
However, `var Inferno = {};` will do nothing.
## Natives
FuseBox automatically imports the following packages:
- `stream`
- `process`
- `Buffer`
- `http`
In some cases, however, you may want to omit them. You can do so by setting `false` on
each package's corresponding key within a `natives` hash:
```js
FuseBox.init({
natives: {
process: false
}
})
```
## Alias
If you are coming from WebPack this feature might be helpful.
```js
FuseBox.init({
alias: {
"faraway": "~/somewhere/far/away/",
},
})
```
* The tilde is required to resolve your `homeDir`
* Aliases will not work with absolute paths (it goes against the concept of FuseBox)
You can also alias npm packages:
```js
FuseBox.init({
alias: {
"babel-utils": "babel/dist/something/here/utils",
},
})
```
Alternatively you can use the chainable API
```js
fuse.bundle("app")
.alias("foo", "~/foo/f")
.alias("bar", "~/bar/b")
```
In your code, you would use it in a way similar to this:
```js
import utils from "babel-utils";
import faraway from "faraway";
console.log(utils, faraway);
```
## Shimming
For those libraries that are bundled to work in `window` (jquery) for example, you need to provide a shimming configuration.
FuseBox will not do analysis on that file, it will simply add it to the top of the bundle.
```js
FuseBox.init({
shim: {
jquery: {
source: "node_modules/jquery/dist/jquery.js",
exports: "$",
},
}
});
```
You can remove `source` option if you load a library using the script tag (for example from a CDN). After it has been shimmed,
you can use FuseBox API, or import/require statement to obtain it.
```js
import * as foo from "jquery";
console.log(foo);
```
The key `jquery` in our case is used to define package name: for example, you can replace `jquery` with `foo` and use `import "foo"` to get a jquery instance.
Example shim config:
```js
shim: {
"react-native-web": { exports: "require('react-native')"},
}
```
Now you can reference it like `window.ReactNative`, and require function is at your convenience.
note: Shims will not be analyzed, which means they should be transpiled before importing, or imported into an environment that does not need them to be transpiled. Shimming works similar to [requirejs](http://requirejs.org/) and [jspm](http://jspm.io/).
For an example, see [shimming in the fuse config](https://github.com/fuse-box/shimming-and-css-example/blob/master/fuse.js#L7) and [how it can be accessed in your code](https://github.com/fuse-box/shimming-and-css-example/blob/master/src/index.ts#L4)
note: Shimming does not work on the server. so if you use shared configuration for both your server and client bundle, remove the shimming option from the global one, and add shim() to your client bundle configuration only. For example:
```js
const fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
});
fuse.bundle("client/app")
.shim({
jquery: {
source: "node_modules/jquery/dist/jquery.js",
exports: "$"
}
})
.instructions(`>app.tsx`);
```