Skip to content
This repository has been archived by the owner on May 17, 2019. It is now read-only.

Add brotli and svgo flags; allow babel excludes; overrideWebpackConfig option in .fusionrc.js #770

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules/
.nyc_output/
yarn-error.log
coverage/
.vscode
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ The CLI interface for Fusion.js

The `fusion-cli` package is responsible for orchestrating compile-time configuration for server and browser bundles, as well as development, test and production variations. It provides a standardized Babel configuration that includes async/await support as well as stage 3+ Ecmascript features.

Due to the complexity involved in configuring many permutations of configurations, Fusion.js does not support custom `webpack.config`. This design decision allows Fusion.js to eventually move away from Webpack if faster and better bundlers become available. Additionally, it allows Fusion.js to make changes to the internal webpack configuration without the concern of breaking users customizations. If you run into a situation where you feel you need to make a webpack customization, please reach out to us on [slack](https://join.slack.com/t/fusionjs/shared_invite/enQtMzk3NjM0MTg0MTI4LWJhNzVjYjk5ZDVlYWIxZWViMjA3YzE5OTc4YWZkNzBkZmNkYmJkMDYyOGEzODEwMzRmMWExMzc1NDIzMmY2NDQ) or create an issue describing your use case.

The CLI is also responsible for hot module reloading in development mode, and for running the web server.

### Installation
Expand Down Expand Up @@ -43,6 +41,9 @@ The CLI API can be most easily run through the Yarn or NPX CLI, e.g. `yarn fusio
- `--log-level`: Log level to output to console `[default: "info"]`
- `--forceLegacyBuild`: Force enable legacy build. By default not compiled in dev.
- `--perserve-names`: Disable name mangling during script minification
- `--no-zofpli`: Disable zopfli compression plugin
- `--no-brotli`: Disable brotli compression plugin
- `--no-svgo`: Disable svgo optimization plugin

<!--
* `fusion profile [--environment] [--watch] [--file-count]`: Profile your application
Expand Down
14 changes: 11 additions & 3 deletions build/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ function getStatsLogger({dir, logger, env}) {

if (err) {
logger.error(err.stack || err);
if (err.details) {
logger.error(err.details);
if ((err /*: any */).details) {
logger.error((err /*: any */).details);
}
return;
}
Expand Down Expand Up @@ -119,6 +119,8 @@ type CompilerOpts = {
logger?: any,
preserveNames?: boolean,
zopfli?: boolean,
brotli?: boolean,
svgo?: boolean,
minify?: boolean
};
*/
Expand All @@ -133,6 +135,8 @@ function Compiler(
watch = false,
logger = console,
zopfli = true,
brotli = true,
svgo = true,
minify = true,
} /*: CompilerOpts */
) /*: CompilerType */ {
Expand Down Expand Up @@ -170,6 +174,8 @@ function Compiler(
legacyPkgConfig,
preserveNames,
zopfli,
brotli,
svgo,
minify,
};

Expand All @@ -180,7 +186,9 @@ function Compiler(

const statsLogger = getStatsLogger({dir, logger, env});

this.on = (type, callback) => compiler.hooks[type].tap('compiler', callback);
this.on = (type, callback) =>
(compiler /*: any */).hooks[type]
.tap('compiler', callback);
this.start = cb => {
cb = cb || function noop(err, stats) {};
// Handler may be called multiple times by `watch`
Expand Down
34 changes: 28 additions & 6 deletions build/get-webpack-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ import type {
FusionRC
} from "./load-fusionrc.js";

import type {
WebpackOptions
} from "webpack";

export type WebpackConfigOpts = {|
id: $Keys<typeof COMPILATIONS>,
dir: string,
Expand All @@ -81,6 +85,8 @@ export type WebpackConfigOpts = {|
watch: boolean,
preserveNames: boolean,
zopfli: boolean,
brotli: boolean,
svgo: boolean,
minify: boolean,
state: {
clientChunkMetadata: ClientChunkMetadataState,
Expand Down Expand Up @@ -108,9 +114,12 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
state,
fusionConfig,
zopfli,
brotli,
svgo,
minify,
legacyPkgConfig = {},
} = opts;

const main = 'src/main.js';

if (!fs.existsSync(path.join(dir, main))) {
Expand Down Expand Up @@ -197,7 +206,8 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
target: runtime === 'server' ? 'node-bundled' : 'browser-legacy',
specOnly: false,
});
return {

const webpackConfig = {
name: runtime,
target: {server: 'node', client: 'web', sw: 'webworker'}[runtime],
entry: {
Expand Down Expand Up @@ -285,7 +295,9 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
runtime === 'server' && {
compiler: id => id === 'server',
test: JS_EXT_PATTERN,
exclude: EXCLUDE_TRANSPILATION_PATTERNS,
exclude:
(fusionConfig.babel && fusionConfig.babel.exclude) ||
EXCLUDE_TRANSPILATION_PATTERNS,
use: [
{
loader: babelLoader.path,
Expand Down Expand Up @@ -315,7 +327,9 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
(runtime === 'client' || runtime === 'sw') && {
compiler: id => id === 'client' || id === 'sw',
test: JS_EXT_PATTERN,
exclude: EXCLUDE_TRANSPILATION_PATTERNS,
exclude:
(fusionConfig.babel && fusionConfig.babel.exclude) ||
EXCLUDE_TRANSPILATION_PATTERNS,
use: [
{
loader: babelLoader.path,
Expand Down Expand Up @@ -345,7 +359,9 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
runtime === 'client' && {
compiler: id => id === 'client-legacy',
test: JS_EXT_PATTERN,
exclude: EXCLUDE_TRANSPILATION_PATTERNS,
exclude:
(fusionConfig.babel && fusionConfig.babel.exclude) ||
EXCLUDE_TRANSPILATION_PATTERNS,
use: [
{
loader: babelLoader.path,
Expand Down Expand Up @@ -457,8 +473,8 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
state.i18nManifest
),
!dev && zopfli && zopfliWebpackPlugin,
!dev && brotliWebpackPlugin,
!dev && svgoWebpackPlugin,
!dev && brotli && brotliWebpackPlugin,
!dev && svgo && svgoWebpackPlugin,
// In development, skip the emitting phase on errors to ensure there are
// no assets emitted that include errors. This fixes an issue with hot reloading
// server side code and recovering from errors correctly. We only want to do this
Expand Down Expand Up @@ -580,6 +596,12 @@ function getWebpackConfig(opts /*: WebpackConfigOpts */) {
: undefined,
},
};

if (fusionConfig.overrideWebpackConfig) {
return fusionConfig.overrideWebpackConfig(webpackConfig);
}

return webpackConfig;
}

// Allow overrides with a warning for `dev` command. In production builds, throw if NODE_ENV is not `production`.
Expand Down
25 changes: 11 additions & 14 deletions build/load-fusionrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ const chalk = require('chalk');
let loggedNotice = false;

/*::
import type {
WebpackOptions
} from "webpack";

export type FusionRC = {
babel?: {plugins?: Array<any>, presets?: Array<any>},
babel?: {plugins?: Array<any>, presets?: Array<any>, exclude?: mixed},
assumeNoImportSideEffects?: boolean,
experimentalCompile?: boolean,
nodeBuiltins?: {[string]: any},
overrideWebpackConfig:? (any) => any
};
*/

Expand All @@ -33,17 +38,6 @@ module.exports = function validateConfig(dir /*: string */) /*: FusionRC */ {
if (!isValid(config)) {
throw new Error('.fusionrc.js is invalid');
}
if (!loggedNotice && config.babel) {
console.log(chalk.dim('Using custom Babel config from .fusionrc.js'));
console.warn(
chalk.yellow(
'Warning: custom Babel config is an',
chalk.bold.underline('unstable API'),
'and may be not be supported in future releases. Use at your own risk.'
)
);
loggedNotice = true;
}
} else {
config = {};
}
Expand All @@ -62,6 +56,7 @@ function isValid(config) {
'assumeNoImportSideEffects',
'experimentalCompile',
'nodeBuiltins',
'overrideWebpackConfig',
].includes(key)
)
) {
Expand All @@ -70,10 +65,12 @@ function isValid(config) {

if (
config.babel &&
!Object.keys(config.babel).every(el => ['plugins', 'presets'].includes(el))
!Object.keys(config.babel).every(el =>
['plugins', 'presets', 'exclude'].includes(el)
)
) {
throw new Error(
`Only "plugins" and "presets" are supported in fusionrc.js babel config`
`Only "plugins", "presets", and "exclude" are supported in fusionrc.js babel config`
);
}

Expand Down
6 changes: 6 additions & 0 deletions commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ exports.run = async function(
preserveNames,
logLevel,
zopfli,
brotli,
svgo,
minify,
} /*: {
dir: string,
production: boolean,
preserveNames: boolean,
logLevel: string,
zopfli: boolean,
brotli: boolean,
svgo: boolean,
minify: boolean
}*/
) {
Expand All @@ -45,6 +49,8 @@ exports.run = async function(
logger,
preserveNames,
zopfli,
brotli,
svgo,
minify,
});

Expand Down
46 changes: 41 additions & 5 deletions docs/fusionrc.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@ This configuration object supports the following fields:

## `babel`

### Adding plugins/presets
### Adding plugins/presets and excluding files from babel compilation

For example, to add your own Babel plugins/preset:

```js
module.exports = {
babel: {
presets: ["some-babel-preset"],
plugins: ["some-babel-plugin"]
plugins: ["some-babel-plugin"],
exclude: moduleName => /\/node_modules\//.test(moduleName)
}
};
```

**Please note that custom Babel config is an unstable API and may not be supported in future releases.**


## `assumeNoImportSideEffects`

By default this is `false`.
Expand All @@ -48,3 +46,41 @@ module.exports = {
}
};
```

## `overrideWebpackConfig`

Allows to customize [webpack configuration](https://webpack.js.org/concepts).

Pass a function that takes a [`webpackConfig`](https://webpack.js.org/configuration/) object created by fusion and return a config with any modifications supported by webpack.

Example:

```js
const SimpleProgressPlugin = require('simple-progress-webpack-plugin');

module.exports = {
overrideWebpackConfig: (webpackConfig) => {
// Debug things:
console.log(webpackConfig);

// Pass your own plugins:
webpackConfig.plugins = webpackConfig.plugins.map(plugin => {
// console.log(plugin.constructor.name);

if (plugin.constructor.name === 'ProgressPlugin') {
return new SimpleProgressPlugin({
format: 'expanded'
})
}

return plugin;
});

// Don't forget to return it
return webpackConfig;
}
};
```