mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[babel] ensure TS preset runs before anything else (#119107)
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
c6db25a3ef
commit
b2f54829d8
7 changed files with 168 additions and 62 deletions
|
@ -6,46 +6,57 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const plugins = [
|
||||
require.resolve('babel-plugin-add-module-exports'),
|
||||
|
||||
// The class properties proposal was merged with the private fields proposal
|
||||
// into the "class fields" proposal. Babel doesn't support this combined
|
||||
// proposal yet, which includes private field, so this transform is
|
||||
// TECHNICALLY stage 2, but for all intents and purposes it's stage 3
|
||||
//
|
||||
// See https://github.com/babel/proposals/issues/12 for progress
|
||||
require.resolve('@babel/plugin-proposal-class-properties'),
|
||||
|
||||
// Optional Chaining proposal is stage 4 (https://github.com/tc39/proposal-optional-chaining)
|
||||
// Need this since we are using TypeScript 3.7+
|
||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||
|
||||
// Nullish coalescing proposal is stage 4 (https://github.com/tc39/proposal-nullish-coalescing)
|
||||
// Need this since we are using TypeScript 3.7+
|
||||
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||
|
||||
// Proposal is on stage 4, and included in ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
|
||||
// Need this since we are using TypeScript 3.8+
|
||||
require.resolve('@babel/plugin-proposal-export-namespace-from'),
|
||||
|
||||
// Proposal is on stage 4, and included in ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
|
||||
// Need this since we are using TypeScript 3.9+
|
||||
require.resolve('@babel/plugin-proposal-private-methods'),
|
||||
|
||||
// It enables the @babel/runtime so we can decrease the bundle sizes of the produced outputs
|
||||
[
|
||||
require.resolve('@babel/plugin-transform-runtime'),
|
||||
{
|
||||
version: '^7.12.5',
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
presets: [
|
||||
[require.resolve('@babel/preset-typescript'), { allowNamespaces: true }],
|
||||
// plugins always run before presets, but in this case we need the
|
||||
// @babel/preset-typescript preset to run first so we have to move
|
||||
// our explicit plugin configs to a sub-preset
|
||||
{
|
||||
plugins: [
|
||||
require.resolve('babel-plugin-add-module-exports'),
|
||||
|
||||
// The class properties proposal was merged with the private fields proposal
|
||||
// into the "class fields" proposal. Babel doesn't support this combined
|
||||
// proposal yet, which includes private field, so this transform is
|
||||
// TECHNICALLY stage 2, but for all intents and purposes it's stage 3
|
||||
//
|
||||
// See https://github.com/babel/proposals/issues/12 for progress
|
||||
require.resolve('@babel/plugin-proposal-class-properties'),
|
||||
|
||||
// Optional Chaining proposal is stage 4 (https://github.com/tc39/proposal-optional-chaining)
|
||||
// Need this since we are using TypeScript 3.7+
|
||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||
|
||||
// Nullish coalescing proposal is stage 4 (https://github.com/tc39/proposal-nullish-coalescing)
|
||||
// Need this since we are using TypeScript 3.7+
|
||||
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||
|
||||
// Proposal is on stage 4, and included in ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
|
||||
// Need this since we are using TypeScript 3.8+
|
||||
require.resolve('@babel/plugin-proposal-export-namespace-from'),
|
||||
|
||||
// Proposal is on stage 4, and included in ECMA-262 (https://github.com/tc39/proposal-export-ns-from)
|
||||
// Need this since we are using TypeScript 3.9+
|
||||
require.resolve('@babel/plugin-proposal-private-methods'),
|
||||
|
||||
// It enables the @babel/runtime so we can decrease the bundle sizes of the produced outputs
|
||||
[
|
||||
require.resolve('@babel/plugin-transform-runtime'),
|
||||
{
|
||||
version: '^7.12.5',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
require.resolve('@babel/preset-react'),
|
||||
|
||||
[
|
||||
require.resolve('@babel/preset-typescript'),
|
||||
{
|
||||
allowNamespaces: true,
|
||||
allowDeclareFields: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins,
|
||||
};
|
||||
|
|
|
@ -35,14 +35,14 @@ export async function runFindBabelHelpersInEntryBundlesCli() {
|
|||
}
|
||||
|
||||
for (const { userRequest } of module.reasons) {
|
||||
if (userRequest.startsWith('@babel/runtime/')) {
|
||||
if (userRequest.startsWith('@babel/runtime')) {
|
||||
imports.add(userRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.success('found', imports.size, '@babel/register imports in entry bundles');
|
||||
log.success('found', imports.size, '@babel/runtime* imports in entry bundles');
|
||||
log.write(
|
||||
Array.from(imports, (i) => `'${i}',`)
|
||||
.sort()
|
||||
|
|
|
@ -26,7 +26,7 @@ export class EmitStatsPlugin {
|
|||
(stats) => {
|
||||
Fs.writeFileSync(
|
||||
Path.resolve(this.bundle.outputDir, 'stats.json'),
|
||||
JSON.stringify(stats.toJson())
|
||||
JSON.stringify(stats.toJson(), null, 2)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
|
|
@ -9,11 +9,13 @@
|
|||
import { externals } from '@kbn/ui-shared-deps-src';
|
||||
import { stringifyRequest } from 'loader-utils';
|
||||
import { resolve } from 'path';
|
||||
import { Configuration, Stats } from 'webpack';
|
||||
import webpack, { Configuration, Stats } from 'webpack';
|
||||
import webpackMerge from 'webpack-merge';
|
||||
import { REPO_ROOT } from './lib/constants';
|
||||
import { IgnoreNotFoundExportPlugin } from './ignore_not_found_export_plugin';
|
||||
|
||||
type Preset = string | [string, Record<string, unknown>] | Record<string, unknown>;
|
||||
|
||||
const stats = {
|
||||
...Stats.presetToOptions('minimal'),
|
||||
colors: true,
|
||||
|
@ -22,6 +24,46 @@ const stats = {
|
|||
moduleTrace: true,
|
||||
};
|
||||
|
||||
function isProgressPlugin(plugin: any) {
|
||||
return 'handler' in plugin && plugin.showActiveModules && plugin.showModules;
|
||||
}
|
||||
|
||||
function isHtmlPlugin(plugin: any): plugin is { options: { template: string } } {
|
||||
return !!(typeof plugin.options?.template === 'string');
|
||||
}
|
||||
|
||||
function isBabelLoaderRule(rule: webpack.RuleSetRule): rule is webpack.RuleSetRule & {
|
||||
use: webpack.RuleSetLoader[];
|
||||
} {
|
||||
return !!(
|
||||
rule.use &&
|
||||
Array.isArray(rule.use) &&
|
||||
rule.use.some(
|
||||
(l) =>
|
||||
typeof l === 'object' && typeof l.loader === 'string' && l.loader.includes('babel-loader')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function getPresetPath(preset: Preset) {
|
||||
if (typeof preset === 'string') return preset;
|
||||
if (Array.isArray(preset)) return preset[0];
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTsPreset(preset: Preset) {
|
||||
if (getPresetPath(preset)?.includes('preset-typescript')) {
|
||||
if (typeof preset === 'string') return [preset, {}];
|
||||
if (Array.isArray(preset)) return preset;
|
||||
|
||||
throw new Error('unsupported preset-typescript format');
|
||||
}
|
||||
}
|
||||
|
||||
function isDesiredPreset(preset: Preset) {
|
||||
return !getPresetPath(preset)?.includes('preset-flow');
|
||||
}
|
||||
|
||||
// Extend the Storybook Webpack config with some customizations
|
||||
/* eslint-disable import/no-default-export */
|
||||
export default function ({ config: storybookConfig }: { config: Configuration }) {
|
||||
|
@ -83,21 +125,72 @@ export default function ({ config: storybookConfig }: { config: Configuration })
|
|||
stats,
|
||||
};
|
||||
|
||||
// Disable the progress plugin
|
||||
const progressPlugin: any = (storybookConfig.plugins || []).find((plugin: any) => {
|
||||
return 'handler' in plugin && plugin.showActiveModules && plugin.showModules;
|
||||
});
|
||||
progressPlugin.handler = () => {};
|
||||
const updatedModuleRules = [];
|
||||
// clone and modify the module.rules config provided by storybook so that the default babel plugins run after the typescript preset
|
||||
for (const originalRule of storybookConfig.module?.rules ?? []) {
|
||||
const rule = { ...originalRule };
|
||||
updatedModuleRules.push(rule);
|
||||
|
||||
// This is the hacky part. We find something that looks like the
|
||||
// HtmlWebpackPlugin and mutate its `options.template` to point at our
|
||||
// revised template.
|
||||
const htmlWebpackPlugin: any = (storybookConfig.plugins || []).find((plugin: any) => {
|
||||
return plugin.options && typeof plugin.options.template === 'string';
|
||||
});
|
||||
if (htmlWebpackPlugin) {
|
||||
htmlWebpackPlugin.options.template = require.resolve('../templates/index.ejs');
|
||||
if (isBabelLoaderRule(rule)) {
|
||||
rule.use = [...rule.use];
|
||||
const loader = (rule.use[0] = { ...rule.use[0] });
|
||||
const options = (loader.options = { ...(loader.options as Record<string, any>) });
|
||||
|
||||
// capture the plugins defined at the root level
|
||||
const plugins: string[] = options.plugins;
|
||||
options.plugins = [];
|
||||
|
||||
// move the plugins to the top of the preset array so they will run after the typescript preset
|
||||
options.presets = [
|
||||
{
|
||||
plugins,
|
||||
},
|
||||
...(options.presets as Preset[]).filter(isDesiredPreset).map((preset) => {
|
||||
const tsPreset = getTsPreset(preset);
|
||||
if (!tsPreset) {
|
||||
return preset;
|
||||
}
|
||||
|
||||
return [
|
||||
tsPreset[0],
|
||||
{
|
||||
...tsPreset[1],
|
||||
allowNamespaces: true,
|
||||
allowDeclareFields: true,
|
||||
},
|
||||
];
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return webpackMerge(storybookConfig, config);
|
||||
// copy and modify the webpack plugins added by storybook
|
||||
const filteredStorybookPlugins = [];
|
||||
for (const plugin of storybookConfig.plugins ?? []) {
|
||||
// Remove the progress plugin
|
||||
if (isProgressPlugin(plugin)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is the hacky part. We find something that looks like the
|
||||
// HtmlWebpackPlugin and mutate its `options.template` to point at our
|
||||
// revised template.
|
||||
if (isHtmlPlugin(plugin)) {
|
||||
plugin.options.template = require.resolve('../templates/index.ejs');
|
||||
}
|
||||
|
||||
filteredStorybookPlugins.push(plugin);
|
||||
}
|
||||
|
||||
return webpackMerge(
|
||||
{
|
||||
...storybookConfig,
|
||||
plugins: filteredStorybookPlugins,
|
||||
module: {
|
||||
...storybookConfig.module,
|
||||
rules: updatedModuleRules,
|
||||
},
|
||||
},
|
||||
config
|
||||
);
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ const MAX_NUMBER_OF_HISTORY_ITEMS = 100;
|
|||
export const isQuotaExceededError = (e: Error): boolean => e.name === 'QuotaExceededError';
|
||||
|
||||
export class History {
|
||||
constructor(private readonly storage: Storage) {}
|
||||
private changeEmitter: BehaviorSubject<any[]>;
|
||||
|
||||
private changeEmitter = new BehaviorSubject<any[]>(this.getHistory() || []);
|
||||
constructor(private readonly storage: Storage) {
|
||||
this.changeEmitter = new BehaviorSubject(this.getHistory() || []);
|
||||
}
|
||||
|
||||
getHistoryKeys() {
|
||||
return this.storage
|
||||
|
|
|
@ -32,7 +32,7 @@ interface State {
|
|||
|
||||
export class DashboardViewport extends React.Component<DashboardViewportProps, State> {
|
||||
static contextType = context;
|
||||
public readonly context!: DashboardReactContextValue;
|
||||
public declare readonly context: DashboardReactContextValue;
|
||||
|
||||
private controlsRoot: React.RefObject<HTMLDivElement>;
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ describe('rolesManagementApp', () => {
|
|||
expect(docTitle.reset).not.toHaveBeenCalled();
|
||||
expect(container).toMatchInlineSnapshot(`
|
||||
<div>
|
||||
Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"fieldCache":{}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}}
|
||||
Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit","search":"","hash":""}}}
|
||||
</div>
|
||||
`);
|
||||
|
||||
|
@ -129,7 +129,7 @@ describe('rolesManagementApp', () => {
|
|||
expect(docTitle.reset).not.toHaveBeenCalled();
|
||||
expect(container).toMatchInlineSnapshot(`
|
||||
<div>
|
||||
Role Edit Page: {"action":"edit","roleName":"role@name","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"fieldCache":{}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@name","search":"","hash":""}}}
|
||||
Role Edit Page: {"action":"edit","roleName":"role@name","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/edit/role@name","search":"","hash":""}}}
|
||||
</div>
|
||||
`);
|
||||
|
||||
|
@ -154,7 +154,7 @@ describe('rolesManagementApp', () => {
|
|||
expect(docTitle.reset).not.toHaveBeenCalled();
|
||||
expect(container).toMatchInlineSnapshot(`
|
||||
<div>
|
||||
Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"fieldCache":{}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/clone/someRoleName","search":"","hash":""}}}
|
||||
Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"userAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"indicesAPIClient":{"fieldCache":{},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}}},"http":{"basePath":{"basePath":"","serverBasePath":""},"anonymousPaths":{},"externalUrl":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}},"history":{"action":"PUSH","length":1,"location":{"pathname":"/clone/someRoleName","search":"","hash":""}}}
|
||||
</div>
|
||||
`);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue