feat(v2): Allow customization of js loader, replace babel by esbuild in Docusaurus website (#4766)

* feat(v2): Allow customization of js loader

* Change API

* use esbuild for Docusaurus website

* Enable isolatedModules: true

* Revert "Enable isolatedModules: true"

This reverts commit e656c350

Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
Sam Zhou 2021-05-14 05:30:34 -04:00 committed by GitHub
parent c8812cf3b5
commit 3548686f59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 113 additions and 11 deletions

View file

@ -3,6 +3,7 @@
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"module": "esnext",
"rootDir": "src",
"outDir": "lib"
}

View file

@ -63,6 +63,9 @@ export interface DocusaurusConfig {
}
)[];
titleDelimiter?: string;
webpack?: {
jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule);
};
}
/**

View file

@ -187,12 +187,14 @@ async function buildLocale({
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
clientConfig,
false,
props.siteConfig.webpack?.jsLoader,
);
serverConfig = applyConfigureWebpack(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
serverConfig,
true,
props.siteConfig.webpack?.jsLoader,
);
}
});

View file

@ -153,6 +153,7 @@ export default async function start(
configureWebpack.bind(plugin), // The plugin lifecycle may reference `this`.
config,
false,
props.siteConfig.webpack?.jsLoader,
);
}
});

View file

@ -134,6 +134,11 @@ const ConfigSchema = Joi.object({
tagline: Joi.string().allow(''),
titleDelimiter: Joi.string().default('|'),
noIndex: Joi.bool().default(false),
webpack: Joi.object({
jsLoader: Joi.alternatives()
.try(Joi.string().equal('babel'), Joi.function())
.optional(),
}).optional(),
});
// TODO move to @docusaurus/utils-validation

View file

@ -81,6 +81,7 @@ describe('base webpack config', () => {
const props = {
outDir: '',
siteDir: '',
siteConfig: {},
baseUrl: '',
generatedFilesDir: '',
routesPaths: '',

View file

@ -5,10 +5,11 @@
* LICENSE file in the root directory of this source tree.
*/
import {validate, Configuration} from 'webpack';
import {validate, Configuration, RuleSetRule} from 'webpack';
import path from 'path';
import {
getCustomizableJSLoader,
applyConfigureWebpack,
applyConfigurePostCss,
getFileLoaderUtils,
@ -18,6 +19,40 @@ import {
ConfigureWebpackFnMergeStrategy,
} from '@docusaurus/types';
describe('customize JS loader', () => {
test('getCustomizableJSLoader defaults to babel loader', () => {
expect(getCustomizableJSLoader()({isServer: true}).loader).toBe(
require.resolve('babel-loader'),
);
expect(getCustomizableJSLoader()({isServer: false}).loader).toBe(
require.resolve('babel-loader'),
);
});
test('getCustomizableJSLoader accepts loaders with preset', () => {
expect(getCustomizableJSLoader('babel')({isServer: true}).loader).toBe(
require.resolve('babel-loader'),
);
expect(getCustomizableJSLoader('babel')({isServer: false}).loader).toBe(
require.resolve('babel-loader'),
);
});
test('getCustomizableJSLoader allows customization', () => {
const customJSLoader = (isServer: boolean): RuleSetRule => ({
loader: 'my-fast-js-loader',
options: String(isServer),
});
expect(getCustomizableJSLoader(customJSLoader)({isServer: true})).toEqual(
customJSLoader(true),
);
expect(getCustomizableJSLoader(customJSLoader)({isServer: false})).toEqual(
customJSLoader(false),
);
});
});
describe('extending generated webpack config', () => {
test('direct mutation on generated webpack config object', async () => {
// fake generated webpack config

View file

@ -11,7 +11,7 @@ import path from 'path';
import {Configuration} from 'webpack';
import {Props} from '@docusaurus/types';
import {
getJSLoader,
getCustomizableJSLoader,
getStyleLoaders,
getFileLoaderUtils,
getCustomBabelConfigFilePath,
@ -73,6 +73,7 @@ export function createBaseConfig(
const {
outDir,
siteDir,
siteConfig,
baseUrl,
generatedFilesDir,
routesPaths,
@ -205,7 +206,7 @@ export function createBaseConfig(
test: /\.(j|t)sx?$/,
exclude: excludeJS,
use: [
getJSLoader({
getCustomizableJSLoader(siteConfig.webpack?.jsLoader)({
isServer,
babelOptions: getCustomBabelConfigFilePath(siteDir),
}),

View file

@ -137,7 +137,7 @@ export function getBabelOptions({
// Name is generic on purpose
// we want to support multiple js loader implementations (babel + esbuild)
export function getJSLoader({
function getDefaultBabelLoader({
isServer,
babelOptions,
}: {
@ -150,6 +150,19 @@ export function getJSLoader({
};
}
export const getCustomizableJSLoader = (
jsLoader: 'babel' | ((isServer: boolean) => RuleSetRule) = 'babel',
) => ({
isServer,
babelOptions,
}: {
isServer: boolean;
babelOptions?: TransformOptions | string;
}): RuleSetRule =>
jsLoader === 'babel'
? getDefaultBabelLoader({isServer, babelOptions})
: jsLoader(isServer);
// TODO remove this before end of 2021?
const warnBabelLoaderOnce = memoize(function () {
console.warn(
@ -163,7 +176,7 @@ const getBabelLoaderDeprecated = function getBabelLoaderDeprecated(
babelOptions?: TransformOptions | string,
) {
warnBabelLoaderOnce();
return getJSLoader({isServer, babelOptions});
return getDefaultBabelLoader({isServer, babelOptions});
};
// TODO remove this before end of 2021 ?
@ -184,17 +197,19 @@ function getCacheLoaderDeprecated() {
* @param configureWebpack a webpack config or a function to modify config
* @param config initial webpack config
* @param isServer indicates if this is a server webpack configuration
* @param jsLoader custom js loader config
* @returns final/ modified webpack config
*/
export function applyConfigureWebpack(
configureWebpack: ConfigureWebpackFn,
config: Configuration,
isServer: boolean,
jsLoader?: 'babel' | ((isServer: boolean) => RuleSetRule),
): Configuration {
// Export some utility functions
const utils: ConfigureWebpackUtils = {
getStyleLoaders,
getJSLoader,
getJSLoader: getCustomizableJSLoader(jsLoader),
getBabelLoader: getBabelLoaderDeprecated,
getCacheLoader: getCacheLoaderDeprecated,
};

View file

@ -63,6 +63,16 @@ const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
: // Production locales
['en', 'fr', 'ko', 'zh-CN'],
},
webpack: {
jsLoader: (isServer) => ({
loader: require.resolve('esbuild-loader'),
options: {
loader: 'tsx',
format: isServer ? 'cjs' : undefined,
target: isServer ? 'node12' : 'es2017',
},
}),
},
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/docusaurus.ico',

View file

@ -39,6 +39,7 @@
"@docusaurus/theme-live-codeblock": "2.0.0-beta.0",
"clsx": "^1.1.1",
"color": "^3.1.3",
"esbuild-loader": "2.13.0",
"netlify-plugin-cache": "^1.0.3",
"npm-to-yarn": "^1.0.0-2",
"react": "^17.0.1",

View file

@ -8060,6 +8060,23 @@ es6-promisify@^5.0.0:
dependencies:
es6-promise "^4.0.3"
esbuild-loader@2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.13.0.tgz#f5a3602a89a3b728506ae3e1887304fffeef9270"
integrity sha512-gC9lML8RGkTSWG2pJVEOZRLMoIluq1Jd7OzzVkOZKMzbMDMWDhXEwXLs60n+aglnAYa9GVrD/UXjTHkM51nBsg==
dependencies:
esbuild "^0.11.19"
joycon "^3.0.1"
json5 "^2.2.0"
loader-utils "^2.0.0"
type-fest "^1.0.1"
webpack-sources "^2.2.0"
esbuild@^0.11.19:
version "0.11.20"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.20.tgz#7cefa1aee8b372c184e42457885f7ce5d3e62a1e"
integrity sha512-QOZrVpN/Yz74xfat0H6euSgn3RnwLevY1mJTEXneukz1ln9qB+ieaerRMzSeETpz/UJWsBMzRVR/andBht5WKw==
escalade@^3.0.2, escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -11823,6 +11840,11 @@ joi@^17.3.0, joi@^17.4.0:
"@sideway/formula" "^3.0.0"
"@sideway/pinpoint" "^2.0.0"
joycon@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.0.1.tgz#9074c9b08ccf37a6726ff74a18485f85efcaddaf"
integrity sha512-SJcJNBg32dGgxhPtM0wQqxqV0ax9k/9TaUskGDSJkSFSQOEWWvQ3zzWdGQRIUry2j1zA5+ReH13t0Mf3StuVZA==
jpeg-js@^0.3.4:
version "0.3.6"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.3.6.tgz#c40382aac9506e7d1f2d856eb02f6c7b2a98b37c"
@ -11981,10 +12003,10 @@ json5@^1.0.1:
dependencies:
minimist "^1.2.0"
json5@^2.1.2:
version "2.1.3"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
json5@^2.1.2, json5@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
dependencies:
minimist "^1.2.5"
@ -19210,6 +19232,11 @@ type-fest@^0.8.0, type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-fest@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.1.1.tgz#210251e7f57357a1457269e6b34837fed067ac2c"
integrity sha512-RPDKc5KrIyKTP7Fk75LruUagqG6b+OTgXlCR2Z0aQDJFeIvL4/mhahSEtHmmVzXu4gmA0srkF/8FCH3WOWxTWA==
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@ -19996,7 +20023,7 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.3:
source-list-map "^2.0.0"
source-map "~0.6.1"
webpack-sources@^2.1.1:
webpack-sources@^2.1.1, webpack-sources@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac"
integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==