Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(v2): Allow configuring babel via babel.config.js #2903

Merged
merged 4 commits into from
Jun 12, 2020
Merged
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
3 changes: 3 additions & 0 deletions packages/docusaurus-init/templates/bootstrap/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
3 changes: 3 additions & 0 deletions packages/docusaurus-init/templates/classic/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
12 changes: 12 additions & 0 deletions packages/docusaurus-init/templates/facebook/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/

module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
69 changes: 69 additions & 0 deletions packages/docusaurus/src/babel/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import path from 'path';
import {ConfigAPI, TransformOptions} from '@babel/core';

function getTransformOptions(isServer: boolean): TransformOptions {
const absoluteRuntimePath = path.dirname(
require.resolve(`@babel/runtime/package.json`),
);
return {
// All optional newlines and whitespace will be omitted when generating code in compact mode
compact: true,
presets: [
isServer
? [
require.resolve('@babel/preset-env'),
{
targets: {
node: 'current',
},
},
]
: [
require.resolve('@babel/preset-env'),
{
useBuiltIns: 'usage',
loose: true,
corejs: '2',
// Do not transform modules to CJS
modules: false,
// Exclude transforms that make all code slower
exclude: ['transform-typeof-symbol'],
},
],
require.resolve('@babel/preset-react'),
require.resolve('@babel/preset-typescript'),
],
plugins: [
// Polyfills the runtime needed for async/await, generators, and friends
// https://babeljs.io/docs/en/babel-plugin-transform-runtime
[
require.resolve('@babel/plugin-transform-runtime'),
{
corejs: false,
helpers: true,
// By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0, better to
// explicitly specify the version so that it can reuse the helper better
// See https://github.com/babel/babel/issues/10261
version: require('@babel/runtime/package.json').version,
regenerator: true,
useESModules: true,
// Undocumented option that lets us encapsulate our runtime, ensuring
// the correct version is used
// https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42
absoluteRuntime: absoluteRuntimePath,
},
],
// Adds syntax support for import()
isServer
? require.resolve('babel-plugin-dynamic-import-node')
: require.resolve('@babel/plugin-syntax-dynamic-import'),
],
};
}

function babelPresets(api: ConfigAPI): TransformOptions {
const caller = api.caller((caller) => caller?.name);
return getTransformOptions(caller === 'server');
}

export = babelPresets;
1 change: 1 addition & 0 deletions packages/docusaurus/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

export const BABEL_CONFIG_FILE_NAME = 'babel.config.js';
export const BUILD_DIR_NAME = 'build';
export const CONFIG_FILE_NAME = 'docusaurus.config.js';
export const GENERATED_FILES_DIR_NAME = '.docusaurus';
Expand Down
18 changes: 15 additions & 3 deletions packages/docusaurus/src/webpack/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {Configuration, Loader} from 'webpack';

import {Props} from '@docusaurus/types';
import {getBabelLoader, getCacheLoader, getStyleLoaders} from './utils';
import {BABEL_CONFIG_FILE_NAME} from '../constants';

const CSS_REGEX = /\.css$/;
const CSS_MODULE_REGEX = /\.module\.css$/;
Expand Down Expand Up @@ -42,6 +43,11 @@ export function createBaseConfig(
const totalPages = routesPaths.length;
const isProd = process.env.NODE_ENV === 'production';

const customBabelConfigurationPath = path.join(
siteDir,
BABEL_CONFIG_FILE_NAME,
);

return {
mode: isProd ? 'production' : 'development',
output: {
Expand Down Expand Up @@ -155,9 +161,15 @@ export function createBaseConfig(
{
test: /\.(j|t)sx?$/,
exclude: excludeJS,
use: [getCacheLoader(isServer), getBabelLoader(isServer)].filter(
Boolean,
) as Loader[],
use: [
getCacheLoader(isServer),
getBabelLoader(
isServer,
fs.existsSync(customBabelConfigurationPath)
? customBabelConfigurationPath
: undefined,
),
].filter(Boolean) as Loader[],
},
{
test: CSS_REGEX,
Expand Down
83 changes: 21 additions & 62 deletions packages/docusaurus/src/webpack/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/

import path from 'path';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import env from 'std-env';
import merge from 'webpack-merge';
import {Configuration, Loader} from 'webpack';
import {TransformOptions} from '@babel/core';

import {version as cacheLoaderVersion} from 'cache-loader/package.json';

Expand Down Expand Up @@ -85,71 +85,30 @@ export function getCacheLoader(
};
}

export function getBabelLoader(isServer: boolean, babelOptions?: {}): Loader {
const absoluteRuntimePath = path.dirname(
require.resolve(`@babel/runtime/package.json`),
);
return {
loader: require.resolve('babel-loader'),
options: Object.assign(
export function getBabelLoader(
isServer: boolean,
babelOptions?: TransformOptions | string,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not worth to keep the babelOptions object here, as it's an internal method and it won't ever be called with an object.

I'd rather have:

export function getBabelLoader({isServer, configFile}: {isServer: boolean, configFile?: string}) {

}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not completely internal. It has been exposed here: https://v2.docusaurus.io/docs/lifecycle-apis#configurewebpackconfig-isserver-utils

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah :) that's fine then, I guess we need to be retrocompatible

): Loader {
let options: TransformOptions;
if (typeof babelOptions === 'string') {
options = {
babelrc: false,
configFile: babelOptions,
caller: {name: isServer ? 'server' : 'client'},
};
} else {
options = Object.assign(
babelOptions ?? {presets: [require.resolve('../babel/preset')]},
{
babelrc: false,
configFile: false,
// All optional newlines and whitespace will be omitted when generating code in compact mode
compact: true,
presets: [
isServer
? [
require.resolve('@babel/preset-env'),
{
targets: {
node: 'current',
},
},
]
: [
require.resolve('@babel/preset-env'),
{
useBuiltIns: 'usage',
loose: true,
corejs: '2',
// Do not transform modules to CJS
modules: false,
// Exclude transforms that make all code slower
exclude: ['transform-typeof-symbol'],
},
],
require.resolve('@babel/preset-react'),
require.resolve('@babel/preset-typescript'),
],
plugins: [
// Polyfills the runtime needed for async/await, generators, and friends
// https://babeljs.io/docs/en/babel-plugin-transform-runtime
[
require.resolve('@babel/plugin-transform-runtime'),
{
corejs: false,
helpers: true,
// By default, it assumes @babel/runtime@7.0.0. Since we use >7.0.0, better to
// explicitly specify the version so that it can reuse the helper better
// See https://github.com/babel/babel/issues/10261
version: require('@babel/runtime/package.json').version,
regenerator: true,
useESModules: true,
// Undocumented option that lets us encapsulate our runtime, ensuring
// the correct version is used
// https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42
absoluteRuntime: absoluteRuntimePath,
},
],
// Adds syntax support for import()
isServer
? require.resolve('babel-plugin-dynamic-import-node')
: require.resolve('@babel/plugin-syntax-dynamic-import'),
],
caller: {name: isServer ? 'server' : 'client'},
},
babelOptions,
),
);
}
return {
loader: require.resolve('babel-loader'),
options,
};
}

Expand Down
12 changes: 12 additions & 0 deletions website/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/

module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
22 changes: 18 additions & 4 deletions website/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ However, it can be helpful if you have a high-level understanding of how the con

The high-level overview of Docusaurus configuration can be categorized into:

- [Site metadata](#site-metadata)
- [Deployment configurations](#deployment-configurations)
- [Theme, plugin, and preset configurations](#theme-plugin-and-preset-configurations)
- [Custom configurations](#custom-configurations)
- [What goes into a `docusaurus.config.js`?](#what-goes-into-a-docusaurusconfigjs)
- [Site metadata](#site-metadata)
- [Deployment configurations](#deployment-configurations)
- [Theme, plugin, and preset configurations](#theme-plugin-and-preset-configurations)
- [Custom configurations](#custom-configurations)
- [Customizing Babel Configuration](#customizing-babel-configuration)

For exact reference to each of the configurable fields, you may refer to [**`docusaurus.config.js` API reference**](docusaurus.config.js.md).

Expand Down Expand Up @@ -149,3 +151,15 @@ const Hello = () => {
If you just want to use those fields on the client side, you could create your own JS files and import them as ES6 modules, there is no need to put them in `docusaurus.config.js`.

:::

## Customizing Babel Configuration

For new Docusaurus projects, we automatically generated a `babel.config.js` in project root.

```js title="babel.config.js"
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

require.resolve() is for yarn2 right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

```

Most of the times, this configuration will work just fine. If you want to customize it, you can directly edit this file to customize babel configuration. For your changes to take effect, you need to restart Docusaurus devserver.