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(webpack): enable babel cache to make rebuild faster #1774

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/sour-lamps-appear.md
@@ -0,0 +1,5 @@
---
'@modern-js/webpack': patch
---

feat(webpack): enable babel cache to make rebuild faster
12 changes: 7 additions & 5 deletions packages/cli/webpack/src/config/features/babel.ts
Expand Up @@ -81,6 +81,7 @@ export function applyScriptCondition({
}

export function applyBabelLoader({
chain,
config,
loaders,
appContext,
Expand All @@ -90,13 +91,14 @@ export function applyBabelLoader({
useTsLoader: boolean;
babelPresetAppOptions?: Partial<BabelPresetAppOptions>;
}) {
const { options, includes, excludes } = getBabelOptions(
appContext.metaName,
appContext.appDirectory,
const { options, includes, excludes } = getBabelOptions({
name: chain.get('name'),
chain: createBabelChain(),
config,
createBabelChain(),
metaName: appContext.metaName,
appDirectory: appContext.appDirectory,
babelPresetAppOptions,
);
});

const rule = loaders
.oneOf(CHAIN_ID.ONE_OF.JS)
Expand Down
102 changes: 82 additions & 20 deletions packages/cli/webpack/src/utils/getBabelOptions.ts
@@ -1,10 +1,12 @@
import path from 'path';
import { isProd, applyOptionsChain, isUseSSRBundle } from '@modern-js/utils';
import {
getBabelConfig,
BabelChain,
Options as BabelPresetAppOptions,
} from '@modern-js/babel-preset-app';
import type { NormalizedConfig, TransformOptions } from '@modern-js/core';
import { CACHE_DIRECTORY } from './constants';

export const getUseBuiltIns = (config: NormalizedConfig) => {
const { polyfill } = config.output || {};
Expand All @@ -14,13 +16,57 @@ export const getUseBuiltIns = (config: NormalizedConfig) => {
return polyfill;
};

export const getBabelOptions = (
metaName: string,
appDirectory: string,
config: NormalizedConfig,
chain: BabelChain,
babelPresetAppOptions?: Partial<BabelPresetAppOptions>,
) => {
function getCacheIdentifier(babelConfig: TransformOptions) {
let cacheIdentifier = process.env.NODE_ENV;

const packages = [
{
name: 'babel-loader',
version: require('../../compiled/babel-loader/package.json').version,
},
{
name: '@modern-js/babel-preset-app',
version:
require('../../package.json').dependencies[
'@modern-js/babel-preset-app'
],
},
];

for (const { name, version } of packages) {
cacheIdentifier += `:${name}@${version}`;
}

const pluginItems = [
...(babelConfig.presets || []),
...(babelConfig.plugins || []),
];
pluginItems.forEach(pluginItem => {
if (Array.isArray(pluginItem)) {
cacheIdentifier += `:${pluginItem[0]}`;
} else {
cacheIdentifier += `:${pluginItem}`;
}
});

return cacheIdentifier;
}

export const getBabelOptions = ({
name,
chain,
config,
metaName,
appDirectory,
babelPresetAppOptions,
}: {
name: string;
chain: BabelChain;
config: NormalizedConfig;
metaName: string;
appDirectory: string;
babelPresetAppOptions?: Partial<BabelPresetAppOptions>;
}) => {
const lodashOptions = applyOptionsChain(
{ id: ['lodash', 'ramda'] },
config.tools?.lodash as any,
Expand Down Expand Up @@ -56,26 +102,42 @@ export const getBabelOptions = (
},
};

const babelOptions: TransformOptions = {
const babelConfig = getBabelConfig({
metaName,
appDirectory,
lodash: lodashOptions,
useLegacyDecorators: !config.output?.enableLatestDecorators,
useBuiltIns: getUseBuiltIns(config),
chain,
styledComponents: styledComponentsOptions,
userBabelConfig: config.tools?.babel,
userBabelConfigUtils: babelUtils,
...babelPresetAppOptions,
});

const babelLoaderOptions: TransformOptions & {
cacheIdentifier?: string;
cacheDirectory?: string;
cacheCompression?: boolean;
} = {
babelrc: false,
configFile: false,
compact: isProd(),
...getBabelConfig({
metaName,
// enable babel loader cache because:
// 1. babel-loader cache can speed up the rebuild time (tested on large projects).
// 2. webpack cache get invalid in many cases, such as config changed, while babel cache is still valid.
cacheIdentifier: getCacheIdentifier(babelConfig),
cacheDirectory: path.resolve(
appDirectory,
lodash: lodashOptions,
useLegacyDecorators: !config.output?.enableLatestDecorators,
useBuiltIns: getUseBuiltIns(config),
chain,
styledComponents: styledComponentsOptions,
userBabelConfig: config.tools?.babel,
userBabelConfigUtils: babelUtils,
...babelPresetAppOptions,
}),
CACHE_DIRECTORY,
`babel/${name}`,
),
cacheCompression: false,
...babelConfig,
};

return {
options: babelOptions,
options: babelLoaderOptions,
includes,
excludes,
};
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/webpack/tests/__snapshots__/utils.test.ts.snap
Expand Up @@ -3,6 +3,9 @@
exports[`getBabelOptions should return babel options as expected 1`] = `
Object {
"babelrc": false,
"cacheCompression": false,
"cacheDirectory": /.cache/babel/client,
"cacheIdentifier": /cli/babel-preset-base/compiled/babel-plugin-styled-components/index.js,
"compact": false,
"configFile": false,
"plugins": Array [
Expand Down
15 changes: 8 additions & 7 deletions packages/cli/webpack/tests/utils.test.ts
Expand Up @@ -35,15 +35,16 @@ describe('mergeRegex', () => {

describe('getBabelOptions', () => {
it('should return babel options as expected', () => {
const { options: babelOptions } = getBabelOptions(
'metaName',
'/root',
{} as any,
createBabelChain(),
{
const { options: babelOptions } = getBabelOptions({
name: 'client',
metaName: 'metaName',
appDirectory: '/root',
config: {} as any,
chain: createBabelChain(),
babelPresetAppOptions: {
target: 'client',
},
);
});

setPathSerializer();
expect(babelOptions).toMatchSnapshot();
Expand Down