chore(NA): upgrade to webpack 5 (#191106)

### Summary

- Closes #89741

This PR contains the resulting work of a massive effort that ports our
on top bundler abstraction (called @kbn/optimizer) from Webpack v4 into
Webpack v5. It's essential in terms of long term maintenance since v4
was not receiving updates any longer but will also unblock some new
features that could be beneficial for our future DevEx endeavours.

Next you can find a small list of all the accomplished tasks on this
journey.

### Completed Tasks
- [x] Upgrade dependencies to match the ones on webpack v5
- [x] Fix null-loader usages
- [x] Fix raw-loader usages
- [x] Fix file-loader usages
- [x] Fix url-loader usages
- [x] Fix `@kbn/optimizer-webpack-helpers` to support webpack v5 
- [x] Adopt previous webpack v4 polyfill-all strategy with
node-polyfill-webpack-plugin
- [x] Fix theme-loader on @kbn/optimizer
- [x] Migrate configurations and ad-hoc loader options on all webpack
configs from v4 to v5
- [x] Fix @kbn/test jest resolver for file-loader cases
- [x] Migrate public-path loader on UiSharedDeps
- [x] Fix all usages of webpack-merge
- [x] Migrate BundleRemoteModule
- [x] Migrate BundleRemotesPlugin
- [x] Correctly migrate PopulateBundleCachePlugin
- [x] Correctly migrate BundleMetricsPlugin
- [x] Check if the profiling plugins still work (--profile flag)
- [x] Recover if possible the previous webpack v4 cacheGroup chunks
rename to something like `data.plugin.chunk.0.js`
- [x] Run `/ci` and make sure we get our first green CI, otherwise work
on the errors until we do
- [x] Profile and solve bottlenecks until we get a cold build
performance similar to the one we had on webpack v4 (`node
scripts/build_kibana_platform_plugins --no-cache`).
- [x] OpenSSL Legacy Warnings: try to remove `--openssl-legacy-provider
` flags
- [x] Add Webpack to Renovate config
- [x] Explore removing `NodePolyfillPlugin`
([here](https://www.npmjs.com/package/node-polyfill-webpack-plugin)) and
add each polyfill needed individually per each webpack config to check
if we get smaller bundles. If we do it's better to go with the case by
case need approach instead of deploying a bunch of polyfills with
NodePolyfillPlugin. As another alternative, create a custom smaller
plugin with only the union of all needed polyfills.
- [x] Evaluate if we want to touch the resolutions on mainFields and
conditionNames
- [x] Understand why `@import 'src/core/public/mixins'` does not work
anymore (not a problem, we should use relative paths anyway but we want
to track why it changed from v4 to v5)
- [x] BUG: Child compilers are having errors hidden and/or changed from
error to warning
- [x] Fix license check for
[Artistic-2.0](https://spdx.org/licenses/Artistic-2.0.html) is the
license for
[domain-browser](https://github.com/bevry/domain-browser?tab=License-1-ov-file).
This package is a dependency of
[NodePolyfillPlugin](https://www.npmjs.com/package/node-polyfill-webpack-plugin).
Artistic 2.0 license is [classified as
yellow](https://github.com/elastic/open-source/blob/main/elastic-product-policy.md#yellow-list)
and should only be used for dev dependencies.
- [x] Make sure `resourceQuery: { not: /raw/ }` is not necessary on
other webpack configs like storybook one
- [x] Find what is being wrongly removed by usedExports optimization;
hint: I believe it is identifying a lot of exports inside the sync entry
of plugins as unused exports and removing them. Then `__kbnBootstrap__`
can't be found
- [x] Rebalance @kbn/optimizer pickMaxWorkerCount
- [x] Re-open the issue to fix sass-warnings
[#190345](https://github.com/elastic/kibana/issues/190345) or downgrade
sass-loader to v10
- [x] Remove previous esm no parse rules
- [x] Confirm esm support is working
- [x] Confirm console override is needed
- [x] Confirm react prod builds on ui shared deps for distributable
- [x] Remove customization for
[xyflow](https://github.com/xyflow/xyflow) from webpack configs
- [x] Clean all the code
- [x] Make sure collected metrics from stats are still aligned with what
we were collecting before; also verify if the modules used for optimizer
caches etc are well generated (@kbn/node-libs-browser)
- [x] Fix watch performance

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Brad White <brad.white@elastic.co>
This commit is contained in:
Tiago Costa 2025-02-14 03:01:36 +00:00 committed by GitHub
parent 200922a512
commit 203bc28478
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
91 changed files with 1907 additions and 951 deletions

View file

@ -2,7 +2,7 @@ steps:
- command: .buildkite/scripts/steps/webpack_bundle_analyzer/build_and_upload.sh
label: 'Build Webpack Bundle Analyzer reports'
agents:
machineType: n2-standard-4
machineType: n2-standard-8
preemptible: true
key: webpack_bundle_analyzer
timeout_in_minutes: 60

View file

@ -39,7 +39,11 @@ const build = () => {
console.log('--- Building Storybooks');
for (const storybook of Object.keys(storybookAliases)) {
exec(`STORYBOOK_BASE_URL=${STORYBOOK_BASE_URL}`, `yarn storybook --site ${storybook}`);
exec(
`STORYBOOK_BASE_URL=${STORYBOOK_BASE_URL}`,
`NODE_OPTIONS=--max-old-space-size=6144`,
`yarn storybook --site ${storybook}`
);
}
};

1
.github/CODEOWNERS vendored
View file

@ -102,6 +102,7 @@ packages/kbn-management/storybook/config @elastic/kibana-management
packages/kbn-manifest @elastic/kibana-core
packages/kbn-mock-idp-plugin @elastic/kibana-security
packages/kbn-mock-idp-utils @elastic/kibana-security
packages/kbn-node-libs-browser-webpack-plugin @elastic/kibana-operations
packages/kbn-openapi-bundler @elastic/security-detection-rule-management
packages/kbn-openapi-generator @elastic/security-detection-rule-management
packages/kbn-optimizer @elastic/kibana-operations

View file

@ -11,7 +11,7 @@ import React from 'react';
import { css } from '@emotion/react';
import { EuiMarkdownFormat } from '@elastic/eui';
// @ts-ignore
import overviewMarkdown from '!!raw-loader!@kbn/embeddable-plugin/README.md';
import overviewMarkdown from '@kbn/embeddable-plugin/README.md?raw';
export const Overview = () => {
return (

View file

@ -10,13 +10,13 @@
import React from 'react';
import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui';
// @ts-ignore
import registerSearchEmbeddableSource from '!!raw-loader!../react_embeddables/search/register_search_embeddable';
import registerSearchEmbeddableSource from '../react_embeddables/search/register_search_embeddable?raw';
// @ts-ignore
import registerAttachActionSource from '!!raw-loader!../react_embeddables/search/register_add_search_panel_action';
import registerAttachActionSource from '../react_embeddables/search/register_add_search_panel_action?raw';
// @ts-ignore
import registerFieldListEmbeddableSource from '!!raw-loader!../react_embeddables/field_list/register_field_list_embeddable';
import registerFieldListEmbeddableSource from '../react_embeddables/field_list/register_field_list_embeddable?raw';
// @ts-ignore
import registerReactEmbeddableSavedObjectSource from '!!raw-loader!../react_embeddables/register_saved_object_example';
import registerReactEmbeddableSavedObjectSource from '../react_embeddables/register_saved_object_example?raw';
export const RegisterEmbeddable = () => {
return (

View file

@ -24,15 +24,15 @@ import { FieldFormatsStart } from '@kbn/field-formats-plugin/public';
import * as example1 from './examples/1_using_existing_format';
import * as example2 from './examples/2_creating_custom_formatter';
// @ts-ignore
import example1SampleCode from '!!raw-loader!./examples/1_using_existing_format';
import example1SampleCode from './examples/1_using_existing_format?raw';
// @ts-ignore
import example2SampleCodePart1 from '!!raw-loader!../common/example_currency_format';
import example2SampleCodePart1 from '../common/example_currency_format?raw';
// @ts-ignore
import example2SampleCodePart2 from '!!raw-loader!./examples/2_creating_custom_formatter';
import example2SampleCodePart2 from './examples/2_creating_custom_formatter?raw';
// @ts-ignore
import example2SampleCodePart3 from '!!raw-loader!../server/examples/2_creating_custom_formatter';
import example2SampleCodePart3 from '../server/examples/2_creating_custom_formatter?raw';
// @ts-ignore
import example3SampleCode from '!!raw-loader!./examples/3_creating_custom_format_editor';
import example3SampleCode from './examples/3_creating_custom_format_editor?raw';
export interface Deps {
fieldFormats: FieldFormatsStart;

View file

@ -60,7 +60,7 @@
"serverless-security": "node scripts/kibana --dev --serverless=security",
"spec_to_console": "node scripts/spec_to_console",
"start": "node scripts/kibana --dev",
"storybook": "node --openssl-legacy-provider scripts/storybook",
"storybook": "node --no-deprecation scripts/storybook",
"test:ftr": "node scripts/functional_tests",
"test:ftr:runner": "node scripts/functional_test_runner",
"test:ftr:server": "node scripts/functional_tests_server",
@ -691,6 +691,7 @@
"@kbn/newsfeed-plugin": "link:src/platform/plugins/shared/newsfeed",
"@kbn/newsfeed-test-plugin": "link:test/common/plugins/newsfeed",
"@kbn/no-data-page-plugin": "link:src/platform/plugins/private/no_data_page",
"@kbn/node-libs-browser-webpack-plugin": "link:packages/kbn-node-libs-browser-webpack-plugin",
"@kbn/notifications-plugin": "link:x-pack/platform/plugins/shared/notifications",
"@kbn/object-utils": "link:src/platform/packages/shared/kbn-object-utils",
"@kbn/object-versioning": "link:src/platform/packages/shared/kbn-object-versioning",
@ -1322,7 +1323,6 @@
"@babel/plugin-proposal-optional-chaining": "^7.21.0",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-transform-class-properties": "^7.24.7",
"@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
"@babel/plugin-transform-numeric-separator": "^7.24.7",
"@babel/plugin-transform-optional-chaining": "^7.24.8",
"@babel/plugin-transform-runtime": "^7.24.7",
@ -1336,7 +1336,7 @@
"@bazel/typescript": "4.6.2",
"@cypress/debugging-proxy": "2.0.1",
"@cypress/grep": "^4.0.1",
"@cypress/webpack-preprocessor": "^6.0.1",
"@cypress/webpack-preprocessor": "^6.0.2",
"@elastic/eslint-plugin-eui": "0.0.2",
"@elastic/makelogs": "^6.1.1",
"@elastic/synthetics": "^1.17.2",
@ -1549,11 +1549,13 @@
"@storybook/addon-storyshots": "^6.5.16",
"@storybook/addons": "^6.5.16",
"@storybook/api": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/client-api": "^6.5.16",
"@storybook/components": "^6.5.16",
"@storybook/core": "^6.5.16",
"@storybook/core-common": "^6.5.16",
"@storybook/core-events": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
"@storybook/node-logger": "^6.5.16",
"@storybook/preview-web": "^6.5.16",
"@storybook/react": "^6.5.16",
@ -1680,11 +1682,10 @@
"@types/vinyl": "^2.0.4",
"@types/vinyl-fs": "^3.0.2",
"@types/watchpack": "^1.1.5",
"@types/webpack": "^4.41.3",
"@types/webpack": "^5.28.5",
"@types/webpack-bundle-analyzer": "^4.7.0",
"@types/webpack-env": "^1.15.3",
"@types/webpack-merge": "^4.1.5",
"@types/webpack-sources": "^0.1.4",
"@types/webpack-env": "^1.18.5",
"@types/webpack-sources": "^3.2.3",
"@types/xml2js": "^0.4.11",
"@types/yargs": "^15.0.0",
"@types/yauzl": "^2.9.1",
@ -1699,12 +1700,13 @@
"autoprefixer": "^10.4.7",
"axe-core": "^4.10.0",
"babel-jest": "^29.7.0",
"babel-loader": "^8.2.5",
"babel-loader": "^9.1.3",
"babel-plugin-add-module-exports": "^1.0.4",
"babel-plugin-istanbul": "^6.1.1",
"babel-plugin-require-context-hook": "^1.0.0",
"babel-plugin-styled-components": "^2.1.4",
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
"babel-plugin-transform-require-default": "^0.1.7",
"babel-plugin-transform-typescript-metadata": "^0.3.2",
"backport": "^9.6.4",
"blob-polyfill": "^7.0.20220408",
@ -1713,12 +1715,12 @@
"chance": "1.0.18",
"chromedriver": "^132.0.0",
"clarify": "^2.2.0",
"clean-webpack-plugin": "^3.0.0",
"clean-webpack-plugin": "^4.0.0",
"cli-progress": "^3.12.0",
"cli-table3": "^0.6.1",
"content-security-policy-parser": "^0.6.0",
"cpy": "^8.1.1",
"css-loader": "^3.4.2",
"css-loader": "^7.1.2",
"cssnano": "^5.1.12",
"cssnano-preset-default": "^5.2.12",
"cssstyle": "^4.1.0",
@ -1756,7 +1758,7 @@
"eslint-traverse": "^1.0.0",
"exit-hook": "^2.2.0",
"expect": "^29.7.0",
"expose-loader": "^0.7.5",
"expose-loader": "^5.0.0",
"express": "^4.21.2",
"fetch-mock": "^10.1.0",
"file-loader": "^4.2.0",
@ -1767,7 +1769,7 @@
"gulp-postcss": "^9.0.1",
"gulp-terser": "^2.1.0",
"has-ansi": "^3.0.0",
"html-loader": "^1.3.2",
"html-loader": "^5.1.0",
"http-proxy": "^1.18.1",
"http2-proxy": "^5.0.53",
"http2-wrapper": "^2.2.1",
@ -1791,10 +1793,9 @@
"license-checker": "^25.0.1",
"listr2": "^8.2.5",
"lmdb": "^2.9.2",
"loader-utils": "^2.0.4",
"marge": "^1.0.1",
"micromatch": "^4.0.8",
"mini-css-extract-plugin": "1.1.0",
"mini-css-extract-plugin": "2.9.1",
"minimist": "^1.2.8",
"mocha": "^10.3.0",
"mocha-junit-reporter": "^2.0.2",
@ -1807,7 +1808,7 @@
"mutation-observer": "^1.0.3",
"native-hdr-histogram": "^1.0.0",
"nock": "12.0.3",
"null-loader": "^3.0.0",
"node-libs-browser": "^2.2.1",
"nyc": "^17.1.0",
"oboe": "^2.1.7",
"openapi-types": "^12.1.3",
@ -1821,12 +1822,11 @@
"playwright-chromium": "1.49.0",
"pngjs": "^7.0.0",
"postcss": "^8.4.31",
"postcss-loader": "^4.2.0",
"postcss-loader": "^8.1.1",
"postcss-prefix-selector": "^1.16.0",
"postcss-scss": "^4.0.4",
"prettier": "^2.8.8",
"proxy": "^2.1.1",
"raw-loader": "^3.1.0",
"react-is": "~18.2.0",
"react-test-renderer": "^17.0.2",
"recast": "^0.23.9",
@ -1834,15 +1834,15 @@
"resolve": "^1.22.0",
"rxjs-marbles": "^7.0.1",
"sass-embedded": "^1.78.0",
"sass-loader": "^10.5.1",
"sass-loader": "^10.5.2",
"selenium-webdriver": "^4.28.0",
"sharp": "0.32.6",
"simple-git": "^3.16.0",
"sinon": "^7.4.2",
"sort-package-json": "^1.53.1",
"source-map": "^0.7.4",
"string-replace-loader": "^2.2.0",
"style-loader": "^1.1.3",
"string-replace-loader": "^3.1.0",
"style-loader": "^4.0.0",
"stylelint": "^14.16.1",
"stylelint-scss": "^4.3.0",
"superagent": "^10.1.1",
@ -1853,25 +1853,23 @@
"table": "^6.8.2",
"tape": "^5.9.0",
"terser": "^5.36.0",
"terser-webpack-plugin": "^4.2.3",
"terser-webpack-plugin": "^5.3.10",
"tough-cookie": "^5.0.0",
"trace": "^3.2.0",
"tree-kill": "^1.2.2",
"ts-morph": "^15.1.0",
"tsd": "^0.31.1",
"typescript": "5.1.6",
"url-loader": "^2.2.0",
"val-loader": "^1.1.1",
"val-loader": "^6.0.0",
"vinyl-fs": "^4.0.0",
"watchpack": "^1.6.0",
"web-streams-polyfill": "^4.0.0",
"webpack": "^4.41.5",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.9.3",
"webpack-merge": "^4.2.2",
"webpack-sources": "^1.4.1",
"webpack-visualizer-plugin2": "^1.1.0",
"webpack": "^5.95.0",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4",
"webpack-merge": "^6.0.1",
"webpack-sources": "^3.2.3",
"xml-crypto": "^6.0.0",
"xmlbuilder": "15.1.1",
"yargs": "^15.4.1",

View file

@ -36,3 +36,15 @@ declare module '*.mdx' {
// eslint-disable-next-line import/no-default-export
export default MDXComponent;
}
declare module '*?asUrl' {
const content: string;
// eslint-disable-next-line import/no-default-export
export default string;
}
declare module '*?raw' {
const content: string;
// eslint-disable-next-line import/no-default-export
export default string;
}

View file

@ -41,6 +41,7 @@ RUNTIME_DEPS = [
"@npm//babel-plugin-styled-components",
"@npm//babel-plugin-transform-react-remove-prop-types",
"@npm//babel-plugin-transform-typescript-metadata",
"@npm//babel-plugin-transform-require-default",
]
js_library(

View file

@ -10,7 +10,12 @@
const { USES_STYLED_COMPONENTS } = require('./styled_components_files');
/** @type {import('@babel/core').ConfigFunction} */
module.exports = (api, options = {}) => {
module.exports = (
api,
options = {
useTransformRequireDefault: false,
}
) => {
return {
presets: [
[
@ -27,6 +32,18 @@ module.exports = (api, options = {}) => {
],
[require('./common_preset'), options],
],
plugins: [
// Conditionally include babel-plugin-transform-require-default
//
// We need to include this plugin in the main worker webpack config that handles our
// non node modules code base in order to support resolving esm
// as a priority over cjs (if that's defined in the mainFields). Without that we might run into
// cases where we have a repo wide cjs code that requires an esm module (coming from the ui-shared-deps that also prioritizes esm)
// which will not be applying the .default key in the require itself.
...(options.useTransformRequireDefault
? [require.resolve('babel-plugin-transform-require-default')]
: []),
],
env: {
production: {
plugins: [

View file

@ -10,6 +10,7 @@
import { v4 as uuid } from 'uuid';
import { defineConfig } from 'cypress';
import wp from '@cypress/webpack-preprocessor';
import { NodeLibsBrowserPlugin } from '@kbn/node-libs-browser-webpack-plugin';
export function defineCypressConfig(options?: Cypress.ConfigOptions<any>) {
return defineConfig({
@ -43,6 +44,7 @@ export function defineCypressConfig(options?: Cypress.ConfigOptions<any>) {
},
],
},
plugins: [new NodeLibsBrowserPlugin()],
},
})(file);
});

View file

@ -13,5 +13,7 @@
"exclude": [
"target/**/*"
],
"kbn_references": []
"kbn_references": [
"@kbn/node-libs-browser-webpack-plugin",
]
}

View file

@ -89,8 +89,8 @@ export const NoBoundaryCrossingRule: Rule.RuleModule = {
return visitAllImportStatements((req, { node, importer, type }) => {
if (
req === null ||
// we can ignore imports using the raw-loader, they will need to be resolved but can be managed on a case by case basis
req.startsWith('!!raw-loader') ||
// we can ignore imports using the ?raw (replacing legacy raw-loader), they will need to be resolved but can be managed on a case by case basis
req.endsWith('?raw') ||
// type only imports can stretch across all the boundaries
isTypeOnlyImport(importer)
) {

View file

@ -39,8 +39,8 @@ export const NoGroupCrossingImportsRule: Rule.RuleModule = {
return visitAllImportStatements((req, { node }) => {
if (
req === null ||
// we can ignore imports using the raw-loader, they will need to be resolved but can be managed on a case by case basis
req.startsWith('!!raw-loader')
// we can ignore imports using the ?raw (replacing legacy raw-loader), they will need to be resolved but can be managed on a case by case basis
req.endsWith('?raw')
) {
return;
}

View file

@ -231,8 +231,8 @@ export class ImportResolver {
resolve(req: string, dirname: string): ResolveResult | null {
// transform webpack loader requests and focus on the actual file selected
const lastExI = req.lastIndexOf('!');
if (lastExI > -1) {
const quesI = req.lastIndexOf('?');
const quesI = req.lastIndexOf('?');
if (lastExI > -1 || quesI > -1) {
const prefix = req.slice(0, lastExI + 1);
const postfix = quesI > -1 ? req.slice(quesI) : '';
const result = this.resolve(req.slice(lastExI + 1, quesI > -1 ? quesI : undefined), dirname);

View file

@ -0,0 +1,40 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "pkg_npm", "ts_project")
SRCS = glob(
[
"**/*.js",
"**/*.ts",
],
exclude = [
"**/*.config.js",
"**/*.mock.*",
"**/*.test.*",
"**/*.stories.*",
"**/__snapshots__/**",
"**/integration_tests/**",
"**/mocks/**",
"**/scripts/**",
"**/storybook/**",
"**/test_fixtures/**",
"**/test_helpers/**",
],
)
BUNDLER_DEPS = [
"@npm//node-libs-browser",
]
filegroup(
name = 'root_pkg_json',
srcs = ["//:package.json"]
)
js_library(
name = "kbn-node-libs-browser-webpack-plugin",
package_name = "@kbn/node-libs-browser-webpack-plugin",
srcs = ["package.json"] + SRCS,
deps = BUNDLER_DEPS,
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,3 @@
# @kbn/node-libs-browser-webpack-plugin
Empty package generated by @kbn/generate

View file

@ -0,0 +1,75 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
/** @typedef {import('webpack').Compiler} WebpackCompiler */
/* eslint-disable import/no-extraneous-dependencies */
// @ts-expect-error
const nodeLibsBrowser = require('node-libs-browser');
const NodeLibsBrowserPlugin = class NodeLibsBrowserPlugin {
/**
* @param {WebpackCompiler} compiler
*/
apply(compiler) {
compiler.options.plugins.push(
new compiler.webpack.ProvidePlugin({
Buffer: [nodeLibsBrowser.buffer, 'Buffer'],
console: nodeLibsBrowser.console,
process: nodeLibsBrowser.process,
})
);
compiler.options.resolve.fallback = {
assert: nodeLibsBrowser.assert,
buffer: nodeLibsBrowser.buffer,
child_process: false,
cluster: false,
console: false,
constants: nodeLibsBrowser.constants,
crypto: nodeLibsBrowser.crypto,
dgram: false,
dns: false,
domain: nodeLibsBrowser.domain,
events: nodeLibsBrowser.events,
fs: false,
http: nodeLibsBrowser.http,
https: nodeLibsBrowser.https,
module: false,
net: false,
os: nodeLibsBrowser.os,
path: nodeLibsBrowser.path,
punycode: nodeLibsBrowser.punycode,
process: nodeLibsBrowser.process,
querystring: nodeLibsBrowser.querystring,
readline: false,
repl: false,
stream: nodeLibsBrowser.stream,
_stream_duplex: nodeLibsBrowser._stream_duplex,
_stream_passthrough: nodeLibsBrowser._stream_passthrough,
_stream_readable: nodeLibsBrowser._stream_readable,
_stream_transform: nodeLibsBrowser._stream_transform,
_stream_writable: nodeLibsBrowser._stream_writable,
string_decoder: nodeLibsBrowser.string_decoder,
sys: nodeLibsBrowser.sys,
timers: nodeLibsBrowser.timers,
tls: false,
tty: nodeLibsBrowser.tty,
url: nodeLibsBrowser.url,
util: nodeLibsBrowser.util,
vm: nodeLibsBrowser.vm,
zlib: nodeLibsBrowser.zlib,
...compiler.options.resolve.fallback,
};
}
};
module.exports = {
NodeLibsBrowserPlugin,
};

View file

@ -7,6 +7,8 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { discoverStorybookConfig } from './discover.webpack';
module.exports = discoverStorybookConfig;
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-node-libs-browser-webpack-plugin'],
};

View file

@ -0,0 +1,5 @@
{
"type": "shared-common",
"id": "@kbn/node-libs-browser-webpack-plugin",
"owner": "@elastic/kibana-operations"
}

View file

@ -0,0 +1,7 @@
{
"name": "@kbn/node-libs-browser-webpack-plugin",
"devOnly": true,
"private": true,
"version": "1.0.0",
"license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0"
}

View file

@ -0,0 +1,18 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"checkJs": true,
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"index.js",
"types.ts"
],
"exclude": [
"target/**/*",
]
}

View file

@ -17,6 +17,8 @@ export type {
} from './src/webpack_helpers';
export {
STATS_WARNINGS_FILTER,
STATS_OPTIONS_DEFAULT_USEFUL_FILTER,
isFailureStats,
failedStatsToErrorMessage,
getModulePath,
@ -25,4 +27,5 @@ export {
isExternalModule,
isIgnoredModule,
isNormalModule,
isRuntimeModule,
} from './src/webpack_helpers';

View file

@ -8,46 +8,31 @@
*/
import webpack from 'webpack';
// @ts-expect-error module is not typed
import Stats from 'webpack/lib/Stats';
export function isFailureStats(stats: webpack.Stats) {
if (stats.hasErrors()) {
return true;
}
const { warnings } = stats.toJson({ all: false, warnings: true });
const { warnings } = stats.toJson({
all: false,
warnings: true,
});
// 1 - when typescript doesn't do a full type check, as we have the ts-loader
// configured here, it does not have enough information to determine
// whether an imported name is a type or not, so when the name is then
// exported, typescript has no choice but to emit the export. Fortunately,
// the extraneous export should not be harmful, so we just suppress these warnings
// https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
//
// 2 - Mini Css Extract plugin tracks the order for each css import we have
// through the project (and it's successive imports) since version 0.4.2.
// In case we have the same imports more than one time with different
// sequences, this plugin will throw a warning. This should not be harmful,
// but the an issue was opened and can be followed on:
// https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250#issuecomment-415345126
const filteredWarnings = Stats.filterWarnings(warnings, STATS_WARNINGS_FILTER);
return filteredWarnings.length > 0;
return warnings && warnings.length > 0;
}
const STATS_WARNINGS_FILTER = new RegExp(
export const STATS_WARNINGS_FILTER = new RegExp(
[
'(export .* was not found in)',
'(export .* was not found in)', // with reexportExportsPresence = false and importExportsPresence = false in the module parser this should not be necessary but looks like it affects performance
'|(chunk .* \\[mini-css-extract-plugin\\]\\\nConflicting order between:)',
].join('')
);
export function failedStatsToErrorMessage(stats: webpack.Stats) {
const details = stats.toString({
...Stats.presetToOptions('minimal'),
...stats.compilation.createStatsOptions('minimal'),
colors: true,
warningsFilter: STATS_WARNINGS_FILTER,
errors: true,
errorDetails: true,
moduleTrace: true,
@ -56,6 +41,21 @@ export function failedStatsToErrorMessage(stats: webpack.Stats) {
return `Optimizations failure.\n${details.split('\n').join('\n ')}`;
}
export const STATS_OPTIONS_DEFAULT_USEFUL_FILTER = {
all: false,
hash: true,
version: true,
timings: true,
assets: true,
modules: true,
reasons: true,
chunks: true,
chunkModules: true,
errorDetails: false,
entrypoints: true,
ids: true,
};
export interface WebpackResolveData {
/** compilation context */
context: string;
@ -103,7 +103,7 @@ export interface WebpackNormalModule {
resource: string;
buildInfo: {
cacheable: boolean;
fileDependencies: Set<string>;
buildDependencies: Set<string>;
};
dependencies: Dependency[];
}
@ -122,7 +122,7 @@ export interface WebpackIgnoredModule {
}
export function isIgnoredModule(module: any): module is WebpackIgnoredModule {
return module?.constructor?.name === 'RawModule' && module.identifierStr?.startsWith('ignored ');
return module?.constructor?.name === 'RawModule' && module.identifierStr?.startsWith('ignored');
}
/** module replacing imports for webpack externals */
@ -169,3 +169,7 @@ export function getModulePath(module: WebpackNormalModule) {
const queryIndex = module.resource.indexOf('?');
return queryIndex === -1 ? module.resource : module.resource.slice(0, queryIndex);
}
export function isRuntimeModule(module: any): boolean {
return module instanceof webpack.RuntimeModule;
}

View file

@ -31,7 +31,7 @@ pageLoadAssetSize:
dataUsage: 30000
dataViewEditor: 28082
dataViewFieldEditor: 42021
dataViewManagement: 5370
dataViewManagement: 6250
dataViews: 65000
dataVisualizer: 30000
devTools: 38637
@ -120,8 +120,8 @@ pageLoadAssetSize:
observabilityShared: 111036
osquery: 107090
painlessLab: 179748
presentationPanel: 11468
presentationUtil: 25000
presentationPanel: 11550
presentationUtil: 33905
productDocBase: 22500
profiling: 36694
remoteClusters: 51327

View file

@ -122,7 +122,7 @@ export class BundleCache {
}
}
public writeWebpackAsset(compilation: webpack.compilation.Compilation) {
public writeWebpackAsset(compilation: webpack.Compilation) {
if (!this.path) {
return;
}

View file

@ -62,12 +62,19 @@ function usingWorkerProc<T>(config: OptimizerConfig, fn: (proc: ChildProcess) =>
const proc = fork(require.resolve('../worker/run_worker'), [], {
execArgv: [
`--require=@kbn/babel-register/install`,
'--openssl-legacy-provider',
...(inspectFlag && config.inspectWorkers
? [`${inspectFlag}=${inspectPortCounter++}`]
: []),
],
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
env: {
// NOTE: with the default 2000 limit we get a lot of recursive watcher recreations (introduced in watchpack v2)
// which makes the experience horrible and the performance between 2.5x to 3x worse when watching.
// If that fails in other mac machines with lower defaults for maxfiles and maxfilesperproc
// or just low powerful ones we need to default to polling instead of relying in the OS events watcher system.
// That can be done in the worker/run_compilers file.
WATCHPACK_WATCHER_LIMIT: '4000',
},
});
return {

View file

@ -22,6 +22,36 @@ jest.mock('os', () => {
cpus() {
return ['foo'] as any;
},
totalmem() {
return 64000000000;
},
freemem() {
return 20000000000;
},
};
});
jest.mock('v8', () => {
return {
...jest.requireActual('v8'),
getHeapStatistics() {
return {
total_heap_size: 5816320,
total_heap_size_executable: 262144,
total_physical_size: 6012928,
total_available_size: 4341242192,
used_heap_size: 4930768,
heap_size_limit: 4345298944,
malloced_memory: 262320,
peak_malloced_memory: 571392,
does_zap_garbage: 0,
number_of_native_contexts: 2,
number_of_detached_contexts: 0,
total_global_handles_size: 8192,
used_global_handles_size: 3296,
external_memory: 2209666,
};
},
};
});

View file

@ -26,15 +26,59 @@ export interface Limits {
};
}
function pickMaxWorkerCount(dist: boolean) {
// don't break if cpus() returns nothing, or an empty array
const cpuCount = Math.max(Os.cpus()?.length, 1);
// if we're buiding the dist then we can use more of the system's resources to get things done a little quicker
const maxWorkers = dist ? cpuCount - 1 : Math.ceil(cpuCount / 3);
// ensure we always have at least two workers
return Math.max(maxWorkers, 2);
interface SystemInfo {
cpuCount: number;
}
function getSystemInfo(): SystemInfo {
// collects useful system information for resource usage calculations
const cpuCount = Math.max(Os.cpus()?.length ?? 0, 1);
return { cpuCount };
}
const pickMaxWorkerCount = (dist: boolean) => {
const isDist = dist;
const isCI = !!process.env.CI;
const isUseMaxAvailableResources = !!process.env.KBN_OPTIMIZER_USE_MAX_AVAILABLE_RESOURCES;
const minWorkers = 2;
const { cpuCount } = getSystemInfo();
const maxWorkers = Math.max(cpuCount - 1, minWorkers);
// In case we get this env var set, just use max workers and avoid any kind of
// resource balance according to memory and cpu
if (isUseMaxAvailableResources) {
return maxWorkers;
}
// Start calculating base worker count
let workerCount;
if (isDist && isCI) {
// For CI dist builds, start with most available resources
workerCount = maxWorkers;
} else if (isDist) {
// For local dist builds, start with 80% of resources but leaving some headroom
workerCount = Math.max(Math.floor(cpuCount * 0.8), 2);
} else {
// For regular local builds, start with fewer resources of 50%
workerCount = Math.max(Math.floor(cpuCount * 0.5), 2);
}
// Adjust by the ratio workerCount to maxWorkers.
// If it is lower or equal to 50% it adds an extra worker
// so the available resources are better used
const ratioWorkerCountToMaxWorkers = 1 - workerCount / maxWorkers;
if (ratioWorkerCountToMaxWorkers >= 0.5) {
workerCount = Math.min(workerCount + 1, cpuCount);
}
// Make sure we respect min and max worker limits
workerCount = Math.max(workerCount, minWorkers);
workerCount = Math.min(workerCount, maxWorkers);
return workerCount;
};
interface Options {
/** absolute path to root of the repo/build */
repoRoot: string;

View file

@ -32,82 +32,90 @@ export class BundleMetricsPlugin {
const { bundle } = this;
compiler.hooks.emit.tap('BundleMetricsPlugin', (compilation) => {
const assets = Object.entries(compilation.assets)
.map(
([name, source]: [string, any]): Asset => ({
name,
size: source.size(),
})
)
.filter((asset) => {
const filename = Path.basename(asset.name);
if (filename.startsWith('.')) {
return false;
compiler.hooks.compilation.tap('BundleMetricsPlugin', (compilation) => {
compilation.hooks.processAssets.tap(
{
name: 'BundleMetricsPlugin',
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ANALYSE,
},
() => {
const assets = Object.entries(compilation.assets)
.map(
([name, source]: [string, any]): Asset => ({
name,
size: source.size(),
})
)
.filter((asset) => {
const filename = Path.basename(asset.name);
if (filename.startsWith('.')) {
return false;
}
const ext = Path.extname(filename);
if (IGNORED_EXTNAME.includes(ext)) {
return false;
}
return true;
});
const entryName = `${bundle.id}.${bundle.type}.js`;
const entry = assets.find((a) => a.name === entryName);
if (!entry) {
throw new Error(
`Unable to find bundle entry named [${entryName}] in [${bundle.outputDir}]`
);
}
const ext = Path.extname(filename);
if (IGNORED_EXTNAME.includes(ext)) {
return false;
const chunkPrefix = `${bundle.id}.chunk.`;
const asyncChunks = assets.filter((a) => a.name.startsWith(chunkPrefix));
const miscFiles = assets.filter((a) => a !== entry && !asyncChunks.includes(a));
const sumSize = (files: Asset[]) => files.reduce((acc: number, a) => acc + a.size, 0);
const moduleCount = bundle.cache.getModuleCount();
if (moduleCount === undefined) {
throw new Error(`moduleCount wasn't populated by PopulateBundleCachePlugin`);
}
return true;
});
const bundleMetrics: CiStatsMetric[] = [
{
group: `@kbn/optimizer bundle module count`,
id: bundle.id,
value: moduleCount,
},
{
group: `page load bundle size`,
id: bundle.id,
value: entry.size,
limit: bundle.pageLoadAssetSizeLimit,
limitConfigPath: `packages/kbn-optimizer/limits.yml`,
},
{
group: `async chunks size`,
id: bundle.id,
value: sumSize(asyncChunks),
},
{
group: `async chunk count`,
id: bundle.id,
value: asyncChunks.length,
},
{
group: `miscellaneous assets size`,
id: bundle.id,
value: sumSize(miscFiles),
},
];
const entryName = `${bundle.id}.${bundle.type}.js`;
const entry = assets.find((a) => a.name === entryName);
if (!entry) {
throw new Error(
`Unable to find bundle entry named [${entryName}] in [${bundle.outputDir}]`
);
}
const metricsSource = new RawSource(JSON.stringify(bundleMetrics, null, 2));
const chunkPrefix = `${bundle.id}.chunk.`;
const asyncChunks = assets.filter((a) => a.name.startsWith(chunkPrefix));
const miscFiles = assets.filter((a) => a !== entry && !asyncChunks.includes(a));
const sumSize = (files: Asset[]) => files.reduce((acc: number, a) => acc + a.size, 0);
const moduleCount = bundle.cache.getModuleCount();
if (moduleCount === undefined) {
throw new Error(`moduleCount wasn't populated by PopulateBundleCachePlugin`);
}
const bundleMetrics: CiStatsMetric[] = [
{
group: `@kbn/optimizer bundle module count`,
id: bundle.id,
value: moduleCount,
},
{
group: `page load bundle size`,
id: bundle.id,
value: entry.size,
limit: bundle.pageLoadAssetSizeLimit,
limitConfigPath: `packages/kbn-optimizer/limits.yml`,
},
{
group: `async chunks size`,
id: bundle.id,
value: sumSize(asyncChunks),
},
{
group: `async chunk count`,
id: bundle.id,
value: asyncChunks.length,
},
{
group: `miscellaneous assets size`,
id: bundle.id,
value: sumSize(miscFiles),
},
];
const metricsSource = new RawSource(JSON.stringify(bundleMetrics, null, 2));
// see https://github.com/jantimon/html-webpack-plugin/blob/33d69f49e6e9787796402715d1b9cd59f80b628f/index.js#L266
// @ts-expect-error undocumented, used to add assets to the output
compilation.emitAsset('metrics.json', metricsSource);
// see https://github.com/jantimon/html-webpack-plugin/blob/33d69f49e6e9787796402715d1b9cd59f80b628f/index.js#L266
// @ts-expect-error undocumented, used to add assets to the output
compilation.emitAsset('metrics.json', metricsSource);
}
);
});
}
}

View file

@ -12,6 +12,7 @@ import { KbnImportReq } from '@kbn/repo-packages';
// @ts-ignore not typed by @types/webpack
import Module from 'webpack/lib/Module';
import { RawSource } from 'webpack-sources';
import { BundleRemote } from '../common';
export class BundleRemoteModule extends Module {
@ -27,8 +28,8 @@ export class BundleRemoteModule extends Module {
return this.req.full;
}
chunkCondition(chunk: any) {
return chunk.hasEntryModule();
chunkCondition(chunk: any, { chunkGraph }: any) {
return chunkGraph.getNumberOfEntryModules(chunk) > 0;
}
identifier() {
@ -39,19 +40,56 @@ export class BundleRemoteModule extends Module {
return this.identifier();
}
needRebuild() {
return false;
needBuild(context: any, callback: any) {
return callback(null, !this.buildMeta);
}
build(_: any, __: any, ___: any, ____: any, callback: () => void) {
this.built = true;
this.buildMeta = {};
this.buildMeta = {
async: false,
exportsType: undefined,
};
this.buildInfo = {
strict: false,
topLevelDeclarations: new Set(),
module: __.outputOptions.module,
exportsArgument: '__webpack_exports__',
};
// super.addDependency(new StaticExportsDependency(true, false));
callback();
}
getConcatenationBailoutReason({ moduleGraph }: any) {
return `@kbn/bundleRemote externals can't be concatenated`;
}
codeGeneration(_: any) {
const sources = new Map();
sources.set(
'javascript',
new RawSource(`
__webpack_require__.r(__webpack_exports__);
var ns = __kbnBundles__.get('${this.remote.bundleType}/${this.remote.bundleId}/${this.req.target}');
Object.defineProperties(__webpack_exports__, Object.getOwnPropertyDescriptors(ns))
`)
);
const data = new Map();
data.set('url', this.req.full);
return {
sources,
runtimeRequirements: new Set([
'module',
'__webpack_exports__',
'__webpack_require__',
// '__webpack_require__.r',
]),
data,
};
}
source() {
return `
__webpack_require__.r(__webpack_exports__);
@ -64,8 +102,8 @@ export class BundleRemoteModule extends Module {
return 42;
}
updateHash(hash: any) {
updateHash(hash: any, context: any) {
hash.update(this.identifier());
super.updateHash(hash);
super.updateHash(hash, context);
}
}

View file

@ -0,0 +1,75 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import NormalizePath from 'normalize-path';
import webpack from 'webpack';
import { Minimatch } from 'minimatch';
import { Bundle } from '../common';
export class BundleRemoteUsedExportsPlugin {
constructor(private readonly bundle: Bundle) {}
apply(compiler: webpack.Compiler) {
const buildPublicDirsPatterns = () => {
const targets = this.bundle.remoteInfo.targets;
const extensions = '.{js,ts,tsx,json}';
const builtPattern = !targets.length
? 'public'
: targets.length === 1
? targets[0]
: `{${targets}}`;
return [`**/${builtPattern}/index${extensions}`, `**/${builtPattern}${extensions}`];
};
const publicDirsPatterns = buildPublicDirsPatterns();
const KbnPluginMainEntryGlob = new Minimatch(publicDirsPatterns[0]);
const KbnPluginExtraFileEntryGlob = new Minimatch(publicDirsPatterns[1]);
compiler.hooks.compilation.tap('MarkExportsAsUsedPlugin', (compilation) => {
const moduleGraph = compilation.moduleGraph;
compilation.hooks.optimizeDependencies.tap('MarkExportsAsUsedPlugin', (modules) => {
Array.from(modules).forEach((module: any) => {
if (!module.resource) {
return;
}
const normalizedModuleResource = NormalizePath(module.resource);
if (
KbnPluginMainEntryGlob.match(normalizedModuleResource) ||
KbnPluginExtraFileEntryGlob.match(normalizedModuleResource)
) {
// Get all exports of the module
const exportsInfo = moduleGraph.getExportsInfo(module);
// If the module uses export *, mark it as used in unknown way
if (module.buildMeta && module.buildMeta.exportsType === 'namespace') {
// @ts-ignore
moduleGraph.getExportsInfo(module).setAllKnownExportsUsed();
// @ts-ignore
moduleGraph.getExportsInfo(module).setUsedInUnknownWay();
moduleGraph.addExtraReason(
module,
`BundleRemoteUsedExportsPlugin/namespace#=>${module.resource}`
);
} else {
Array.from(exportsInfo.exports).forEach((exportInfo) => {
if (exportInfo.name) {
moduleGraph.getExportsInfo(module).setUsedInUnknownWay(exportInfo.name);
moduleGraph.addExtraReason(
module,
`BundleRemoteUsedExportsPlugin/${exportInfo.name}#=>${module.resource}`
);
}
});
}
}
});
});
});
}
}

View file

@ -21,7 +21,6 @@ interface RequestData {
}
type Callback<T> = (error?: any, result?: T) => void;
type ModuleFactory = (data: RequestData, callback: Callback<BundleRemoteModule>) => void;
export class BundleRemotesPlugin {
private allowedBundleIds = new Set<string>();
@ -40,34 +39,33 @@ export class BundleRemotesPlugin {
// hook into the creation of NormalModule instances in webpack, if the import
// statement leading to the creation of the module is pointing to a bundleRef
// entry then create a BundleRefModule instead of a NormalModule.
compilationParams.normalModuleFactory.hooks.factory.tap(
'BundleRefsPlugin/normalModuleFactory/factory',
(wrappedFactory: ModuleFactory): ModuleFactory =>
(data, callback) => {
const { request } = data.dependencies[0];
compilationParams.normalModuleFactory.hooks.factorize.tapAsync(
'BundleRefsPlugin/normalModuleFactory/factorize',
(data: RequestData, callback: Callback<BundleRemoteModule>) => {
const { request } = data.dependencies[0];
const cached = moduleCache.get(request);
if (cached === null) {
return wrappedFactory(data, callback);
}
if (cached !== undefined) {
return callback(null, cached);
}
this.resolve(request, (error, result) => {
if (error || result === undefined) {
return callback(error);
}
moduleCache.set(request, result);
if (result === null) {
return wrappedFactory(data, callback);
}
callback(null, result);
});
const cached = moduleCache.get(request);
if (cached === null) {
return callback();
}
if (cached !== undefined) {
return callback(null, cached);
}
this.resolve(request, (error, result) => {
if (error || result === undefined) {
return callback(error);
}
moduleCache.set(request, result);
if (result === null) {
return callback();
}
callback(null, result);
});
}
);
});
@ -87,7 +85,7 @@ export class BundleRemotesPlugin {
compilation.hooks.finishModules.tapPromise(
'BundleRefsPlugin/finishModules',
async (modules) => {
const usedBundleIds = (modules as any[])
const usedBundleIds = (Array.from(modules) as any[])
.filter((m: any): m is BundleRemoteModule => m instanceof BundleRemoteModule)
.map((m) => m.remote.bundleId);
@ -96,7 +94,7 @@ export class BundleRemotesPlugin {
.join(', ');
if (unusedBundleIds) {
const error = new Error(
const error = new webpack.WebpackError(
`Bundle for [${this.bundle.id}] lists [${unusedBundleIds}] as a required bundle, but does not use it. Please remove it.`
);
(error as any).file = manifestPath;
@ -108,7 +106,9 @@ export class BundleRemotesPlugin {
}
public resolve(request: string, cb: (error?: Error, bundle?: null | BundleRemoteModule) => void) {
if (request.endsWith('.json')) {
// NOTE: previously on webpack v4 ?raw files did not reach this phase and were excluded
// which is not the case anymore in webpack v5 so we need to do exclude them from being resolved
if (request.endsWith('.json') || request.endsWith('?raw')) {
return cb(undefined, null);
}

View file

@ -11,7 +11,7 @@ import Fs from 'fs';
import Path from 'path';
import webpack from 'webpack';
import { STATS_OPTIONS_DEFAULT_USEFUL_FILTER } from '@kbn/optimizer-webpack-helpers';
import { Bundle } from '../common';
export class EmitStatsPlugin {
@ -27,7 +27,7 @@ export class EmitStatsPlugin {
(stats) => {
Fs.writeFileSync(
Path.resolve(this.bundle.outputDir, 'stats.json'),
JSON.stringify(stats.toJson(), null, 2)
JSON.stringify(stats.toJson(STATS_OPTIONS_DEFAULT_USEFUL_FILTER), null, 2)
);
}
);

View file

@ -8,7 +8,7 @@
*/
import Path from 'path';
import { inspect } from 'util';
import { inspect, promisify } from 'util';
import webpack from 'webpack';
import {
@ -17,6 +17,7 @@ import {
isIgnoredModule,
isConcatenatedModule,
isDelegatedModule,
isRuntimeModule,
getModulePath,
} from '@kbn/optimizer-webpack-helpers';
@ -30,6 +31,14 @@ import {
} from '../common';
import { BundleRemoteModule } from './bundle_remote_module';
interface InputFileSystem {
readFile: (
path: string,
encoding: null | undefined,
callback: (err: Error | null, stats: Buffer) => void
) => void;
}
/**
* sass-loader creates about a 40% overhead on the overall optimizer runtime, and
* so this constant is used to indicate to assignBundlesToWorkers() that there is
@ -48,117 +57,157 @@ export class PopulateBundleCachePlugin {
public apply(compiler: webpack.Compiler) {
const { bundle, workerConfig } = this;
const inputFs = compiler.inputFileSystem as InputFileSystem;
if (!inputFs) {
throw new Error('expected inputFs to be defined');
}
const readFile = promisify(inputFs.readFile);
const moduleFileDepsMap = new Map();
const allFileDepsPathSet = new Set();
compiler.hooks.emit.tap(
{
name: 'PopulateBundleCachePlugin',
before: ['BundleMetricsPlugin'],
},
(compilation) => {
const bundleRefExportIds: string[] = [];
let moduleCount = 0;
let workUnits = compilation.fileDependencies.size;
compiler.hooks.compilation.tap('PopulateBundleCachePlugin', (compilation) => {
const hooks = webpack.NormalModule.getCompilationHooks(compilation);
const paths = new Set<string>();
const rawHashes = new Map<string, string | null>();
const addReferenced = (path: string) => {
if (paths.has(path)) {
return;
// first collect file deps for modules
hooks.beforeSnapshot.tap('PopulateBundleCachePlugin', (module: any) => {
// make sure we have file deps for this module
if (module.buildInfo.fileDependencies.size > 0) {
const realFileDeps = [];
for (const path of module.buildInfo.fileDependencies) {
// in webpack v5 there a lot of paths collected that are not real files
// but instead folders or partial paths.
// Here we're verifying if what we have as indeed a filepath
if (Path.extname(path).length > 0) {
realFileDeps.push(path);
allFileDepsPathSet.add(path);
}
}
paths.add(path);
let content: Buffer;
try {
content = compiler.inputFileSystem.readFileSync(path);
} catch {
return rawHashes.set(path, null);
}
return rawHashes.set(path, Hashes.hash(content));
};
const dllRefKeys = new Set<string>();
if (bundle.manifestPath) {
addReferenced(bundle.manifestPath);
moduleFileDepsMap.set(module.identifier(), realFileDeps);
}
});
for (const module of compilation.modules) {
if (isNormalModule(module)) {
moduleCount += 1;
const path = getModulePath(module);
const parsedPath = parseFilePath(path);
// in the end process assets to calculate workUnites and references
compilation.hooks.processAssets.tapAsync(
{
name: 'PopulateBundleCachePlugin',
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_DEV_TOOLING,
},
async (_, callback) => {
const bundleRefExportIds: string[] = [];
let moduleCount = 0;
let workUnits = allFileDepsPathSet.size;
// TODO: Does this need to be updated to support @kbn/ packages?
if (!parsedPath.dirs.includes('node_modules')) {
addReferenced(path);
const paths = new Set<string>();
const rawHashes = new Map<string, string | null>();
const addReferenced = async (path: string) => {
if (paths.has(path)) {
return;
}
if (path.endsWith('.scss')) {
workUnits += EXTRA_SCSS_WORK_UNITS;
paths.add(path);
let content: Buffer;
try {
content = await readFile(path, null);
} catch {
return rawHashes.set(path, null);
}
for (const depPath of module.buildInfo.fileDependencies) {
addReferenced(depPath);
}
return rawHashes.set(path, Hashes.hash(content));
};
const dllRefKeys = new Set<string>();
if (bundle.manifestPath) {
await addReferenced(bundle.manifestPath);
workUnits += 1;
}
for (const module of compilation.modules) {
if (isNormalModule(module)) {
const path = getModulePath(module);
if (Path.extname(path).length === 0) {
continue;
}
moduleCount += 1;
const parsedPath = parseFilePath(path);
if (!parsedPath.dirs.includes('node_modules')) {
await addReferenced(path);
if (path.endsWith('.scss')) {
workUnits += EXTRA_SCSS_WORK_UNITS;
const dependencies = moduleFileDepsMap.get(module.identifier());
if (dependencies) {
await Promise.all(
dependencies.map((depPath: string) => addReferenced(depPath))
);
}
}
continue;
}
const nmIndex = parsedPath.dirs.lastIndexOf('node_modules');
const isScoped = parsedPath.dirs[nmIndex + 1].startsWith('@');
const pkgJsonPath = Path.join(
parsedPath.root,
...parsedPath.dirs.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)),
'package.json'
);
await addReferenced(pkgJsonPath);
continue;
}
const nmIndex = parsedPath.dirs.lastIndexOf('node_modules');
const isScoped = parsedPath.dirs[nmIndex + 1].startsWith('@');
const pkgJsonPath = Path.join(
parsedPath.root,
...parsedPath.dirs.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)),
'package.json'
);
addReferenced(pkgJsonPath);
continue;
if (module instanceof BundleRemoteModule) {
bundleRefExportIds.push(module.req.full);
continue;
}
if (isConcatenatedModule(module)) {
moduleCount += 1;
continue;
}
if (isDelegatedModule(module)) {
dllRefKeys.add(module.userRequest);
continue;
}
if (isExternalModule(module) || isIgnoredModule(module) || isRuntimeModule(module)) {
continue;
}
throw new Error(`Unexpected module type: ${inspect(module)}`);
}
if (module instanceof BundleRemoteModule) {
bundleRefExportIds.push(module.req.full);
continue;
}
const referencedPaths = Array.from(paths).sort(ascending((p) => p));
const sortedDllRefKeys = Array.from(dllRefKeys).sort(ascending((p) => p));
if (isConcatenatedModule(module)) {
moduleCount += module.modules.length;
continue;
}
if (isDelegatedModule(module)) {
// delegated modules are the references to the ui-shared-deps-npm dll
dllRefKeys.add(module.userRequest);
continue;
}
if (isExternalModule(module) || isIgnoredModule(module)) {
continue;
}
throw new Error(`Unexpected module type: ${inspect(module)}`);
}
const referencedPaths = Array.from(paths).sort(ascending((p) => p));
const sortedDllRefKeys = Array.from(dllRefKeys).sort(ascending((p) => p));
bundle.cache.set({
remoteBundleImportReqs: bundleRefExportIds.sort(ascending((p) => p)),
optimizerCacheKey: workerConfig.optimizerCacheKey,
cacheKey: bundle.createCacheKey(
bundle.cache.set({
remoteBundleImportReqs: bundleRefExportIds.sort(ascending((p) => p)),
optimizerCacheKey: workerConfig.optimizerCacheKey,
cacheKey: bundle.createCacheKey(
referencedPaths,
new Hashes(rawHashes),
this.dllManifest,
sortedDllRefKeys
),
moduleCount,
workUnits,
referencedPaths,
new Hashes(rawHashes),
this.dllManifest,
sortedDllRefKeys
),
moduleCount,
workUnits,
referencedPaths,
dllRefKeys: sortedDllRefKeys,
});
dllRefKeys: sortedDllRefKeys,
});
// write the cache to the compilation so that it isn't cleaned by clean-webpack-plugin
bundle.cache.writeWebpackAsset(compilation);
}
);
// write the cache to the compilation so that it isn't cleaned by clean-webpack-plugin
bundle.cache.writeWebpackAsset(compilation);
callback();
}
);
});
}
}

View file

@ -53,7 +53,6 @@ const observeCompiler = (
*/
const complete$ = Rx.fromEventPattern<Stats>((cb) => done.tap(PLUGIN_NAME, cb)).pipe(
maybeMap((stats) => {
// @ts-expect-error not included in types, but it is real https://github.com/webpack/webpack/blob/ab4fa8ddb3f433d286653cd6af7e3aad51168649/lib/Watching.js#L58
if (stats.compilation.needAdditionalPass) {
return undefined;
}

View file

@ -7,7 +7,6 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { stringifyRequest, getOptions } from 'loader-utils';
import webpack from 'webpack';
import {
FALLBACK_THEME_TAG,
@ -15,11 +14,17 @@ import {
hasNonDefaultThemeTags,
} from '@kbn/core-ui-settings-common';
const getStringifiedRequest = (loaderContext: webpack.LoaderContext<any>, request: string) => {
return JSON.stringify(
loaderContext.utils.contextify(loaderContext.context || loaderContext.rootContext, request)
);
};
// eslint-disable-next-line import/no-default-export
export default function (this: webpack.loader.LoaderContext) {
export default function (this: webpack.LoaderContext<any>) {
this.cacheable(true);
const options = getOptions(this);
const options = this.getOptions();
const bundleId = options.bundleId as string;
const themeTags = parseThemeTags(options.themeTags);
const isFallbackNeeded = hasNonDefaultThemeTags(themeTags);
@ -38,7 +43,10 @@ export default function (this: webpack.loader.LoaderContext) {
defaultClause = `
default:
console.error(new Error("SASS files in [${bundleId}] were not built for theme [" + window.__kbnThemeTag__ + "]. Styles were compiled using the [${FALLBACK_THEME_TAG}] theme instead to keep Kibana somewhat usable. Please adjust the advanced settings to make use of [${themeTags}] or make sure the KBN_OPTIMIZER_THEMES environment variable includes [" + window.__kbnThemeTag__ + "] in a comma-separated list of themes you want to compile. You can also set it to \'*\' to build all themes."));
return require(${stringifyRequest(this, `${this.resourcePath}?${FALLBACK_THEME_TAG}`)});`;
return require(${getStringifiedRequest(
this,
`${this.resourcePath}?${FALLBACK_THEME_TAG}`
)});`;
}
return `
@ -47,7 +55,7 @@ ${themeTags
.map(
(tag) => `
case '${tag}':
return require(${stringifyRequest(this, `${this.resourcePath}?${tag}`)});`
return require(${getStringifiedRequest(this, `${this.resourcePath}?${tag}`)});`
)
.join('\n')}
${defaultClause}

View file

@ -10,22 +10,24 @@
import Path from 'path';
import Fs from 'fs';
import { stringifyRequest } from 'loader-utils';
import webpack from 'webpack';
// @ts-expect-error
import TerserPlugin from 'terser-webpack-plugin';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import UiSharedDepsNpm from '@kbn/ui-shared-deps-npm';
import * as UiSharedDepsSrc from '@kbn/ui-shared-deps-src';
import StatoscopeWebpackPlugin from '@statoscope/webpack-plugin';
// @ts-expect-error
import VisualizerPlugin from 'webpack-visualizer-plugin2';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import {
STATS_WARNINGS_FILTER,
STATS_OPTIONS_DEFAULT_USEFUL_FILTER,
} from '@kbn/optimizer-webpack-helpers';
import { NodeLibsBrowserPlugin } from '@kbn/node-libs-browser-webpack-plugin';
import { Bundle, BundleRemotes, WorkerConfig, parseDllManifest } from '../common';
import { BundleRemotesPlugin } from './bundle_remotes_plugin';
import { BundleMetricsPlugin } from './bundle_metrics_plugin';
import { BundleRemoteUsedExportsPlugin } from './bundle_remote_used_exports_plugin';
import { EmitStatsPlugin } from './emit_stats_plugin';
import { PopulateBundleCachePlugin } from './populate_bundle_cache_plugin';
@ -40,31 +42,34 @@ export function getWebpackConfig(
const ENTRY_CREATOR = require.resolve('./entry_point_creator');
const commonConfig: webpack.Configuration = {
node: { fs: 'empty' },
context: bundle.contextDir,
cache: true,
entry: {
[bundle.id]: ENTRY_CREATOR,
},
devtool: worker.dist ? false : '#cheap-source-map',
devtool: worker.dist ? false : 'cheap-source-map',
profile: worker.profileWebpack,
target: 'web',
output: {
hashFunction: 'sha1',
hashFunction: 'xxhash64',
path: bundle.outputDir,
filename: `${bundle.id}.${bundle.type}.js`,
chunkFilename: `${bundle.id}.chunk.[id].js`,
devtoolModuleFilenameTemplate: (info) =>
devtoolModuleFilenameTemplate: (info: any) =>
`/${bundle.type}:${bundle.id}/${Path.relative(
bundle.sourceRoot,
info.absoluteResourcePath
)}${info.query}`,
jsonpFunction: `${bundle.id}_bundle_jsonpfunction`,
chunkLoadingGlobal: `${bundle.id}_bundle_jsonpfunction`,
chunkLoading: 'jsonp',
},
optimization: {
noEmitOnErrors: true,
moduleIds: worker.dist ? 'deterministic' : 'natural',
chunkIds: worker.dist ? 'deterministic' : 'natural',
emitOnErrors: false,
splitChunks: {
maxAsyncRequests: 10,
cacheGroups: {
@ -75,9 +80,13 @@ export function getWebpackConfig(
},
},
externals: UiSharedDepsSrc.externals,
externals: {
'node:crypto': 'commonjs crypto',
...UiSharedDepsSrc.externals,
},
plugins: [
new NodeLibsBrowserPlugin(),
new CleanWebpackPlugin(),
new BundleRemotesPlugin(bundle, bundleRemotes),
new PopulateBundleCachePlugin(worker, bundle, parseDllManifest(DLL_MANIFEST)),
@ -86,24 +95,22 @@ export function getWebpackConfig(
context: worker.repoRoot,
manifest: DLL_MANIFEST,
}),
// @ts-ignore something is wrong with the StatoscopeWebpackPlugin type.
...(worker.profileWebpack
...((worker.profileWebpack
? [
new EmitStatsPlugin(bundle),
new StatoscopeWebpackPlugin({
open: false,
saveReportTo: `${bundle.outputDir}/${bundle.id}.statoscope.html`,
}),
new VisualizerPlugin({ filename: `${bundle.id}.visualizer.html` }),
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: `${bundle.id}.analyzer.html`,
openAnalyzer: false,
logLevel: 'silent',
}),
new StatoscopeWebpackPlugin({
open: false,
saveReportTo: `${bundle.outputDir}/${bundle.id}.statoscope.html`,
statsOptions: STATS_OPTIONS_DEFAULT_USEFUL_FILTER,
}),
]
: []),
// @ts-ignore something is wrong with the StatoscopeWebpackPlugin type.
: []) as any),
...(bundle.banner ? [new webpack.BannerPlugin({ banner: bundle.banner, raw: true })] : []),
],
@ -199,14 +206,17 @@ export function getWebpackConfig(
{
loader: 'sass-loader',
options: {
additionalData(content: string, loaderContext: webpack.loader.LoaderContext) {
return `@import ${stringifyRequest(
loaderContext,
Path.resolve(
worker.repoRoot,
`src/core/public/styles/core_app/_globals_${theme}.scss`
additionalData(content: string, loaderContext: webpack.LoaderContext<any>) {
const req = JSON.stringify(
loaderContext.utils.contextify(
loaderContext.context || loaderContext.rootContext,
Path.resolve(
worker.repoRoot,
`src/core/public/styles/core_app/_globals_${theme}.scss`
)
)
)};\n${content}`;
);
return `@import ${req};\n${content}`;
},
implementation: require('sass-embedded'),
sassOptions: {
@ -228,13 +238,6 @@ export function getWebpackConfig(
},
],
},
{
test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/,
loader: 'url-loader',
options: {
limit: 8192,
},
},
{
test: /\.(js|tsx?)$/,
exclude: /node_modules/,
@ -243,67 +246,47 @@ export function getWebpackConfig(
options: {
babelrc: false,
envName: worker.dist ? 'production' : 'development',
presets: [BABEL_PRESET],
presets: [[BABEL_PRESET, { useTransformRequireDefault: true }]],
},
},
},
{
test: /node_modules\/@?xstate5\/.*\.js$/,
use: {
loader: 'babel-loader',
options: {
babelrc: false,
envName: worker.dist ? 'production' : 'development',
presets: [BABEL_PRESET],
plugins: ['@babel/plugin-transform-logical-assignment-operators'],
},
},
},
{
test: /\.js$/,
include: /node_modules[\\\/]@dagrejs/,
use: {
loader: 'babel-loader',
options: {
envName: worker.dist ? 'production' : 'development',
presets: ['@babel/preset-env'], // Doesn't work with BABEL_PRESET
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
},
{
test: /node_modules[\/\\]@?xyflow[\/\\].*.js$/,
loaders: 'babel-loader',
options: {
envName: worker.dist ? 'production' : 'development',
presets: [BABEL_PRESET],
plugins: ['@babel/plugin-transform-logical-assignment-operators'],
},
},
{
test: /node_modules[\/\\]launchdarkly[^\/\\]+[\/\\].*.js$/,
loaders: 'babel-loader',
options: {
envName: worker.dist ? 'production' : 'development',
presets: [BABEL_PRESET],
},
},
{
test: /\.(html|md|txt|tmpl)$/,
use: {
loader: 'raw-loader',
},
},
{
test: /\.peggy$/,
loader: require.resolve('@kbn/peggy-loader'),
},
// emits a separate file and exports the URL. Previously achievable by using file-loader.
{
include: [
require.resolve('@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js'),
require.resolve('maplibre-gl/dist/maplibre-gl-csp-worker'),
],
type: 'asset/resource',
},
// exports the source code of the asset. Previously achievable by using raw-loader.
{
resourceQuery: /raw/,
type: 'asset/source',
},
{
test: /\.(html|md|txt|tmpl)$/,
type: 'asset/source',
},
// automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using url-loader with asset size limit.
{
test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8192,
},
},
},
],
},
resolve: {
extensions: ['.js', '.ts', '.tsx', '.json'],
mainFields: ['browser', 'main'],
mainFields: ['browser', 'module', 'main'],
alias: {
core_app_image_assets: Path.resolve(
worker.repoRoot,
@ -323,16 +306,43 @@ export function getWebpackConfig(
// and not for the webpack compilations performance itself
hints: false,
},
ignoreWarnings: [STATS_WARNINGS_FILTER],
};
const nonDistributableConfig: webpack.Configuration = {
mode: 'development',
cache: {
type: 'memory',
cacheUnaffected: true,
},
experiments: {
cacheUnaffected: true,
backCompat: false,
},
optimization: {
sideEffects: false,
removeAvailableModules: false,
},
module: {
// This was default on webpack v4
unsafeCache: true,
},
};
const distributableConfig: webpack.Configuration = {
mode: 'production',
plugins: [
// NOTE: this plugin is needed to mark exports on public and extraPublicDir entry files
// as used otherwise the new webpack v5 aggressive exports analysis will mark them as unused
// and they will be removed. Without this plugin we need to run with usedExports: false which
// affects the bundle sizes by a big margin.
new BundleRemoteUsedExportsPlugin(bundle),
new webpack.DefinePlugin({
'process.env': {
IS_KIBANA_DISTRIBUTABLE: `"true"`,
@ -343,8 +353,6 @@ export function getWebpackConfig(
optimization: {
minimizer: [
new TerserPlugin({
cache: false,
sourceMap: false,
extractComments: false,
parallel: false,
terserOptions: {

View file

@ -30,5 +30,6 @@
"@kbn/dev-cli-runner",
"@kbn/jest-serializers",
"@kbn/repo-packages",
"@kbn/node-libs-browser-webpack-plugin",
]
}

View file

@ -2,6 +2,7 @@ load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
SRCS = glob(
[
"**/*.js",
"**/*.ts",
],
exclude = [

View file

@ -8,10 +8,12 @@
*/
import { getJsSource } from '@kbn/peggy';
import webpack from 'webpack';
// eslint-disable-next-line import/no-default-export
export default function (this: webpack.loader.LoaderContext) {
/**
* @this {import('webpack').LoaderContext<any>}
*/
export default function () {
this.cacheable(true);
const callback = this.async();

View file

@ -1,6 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"checkJs": true,
"outDir": "target/types",
"types": [
"jest",
@ -9,11 +10,12 @@
},
"include": [
"**/*.ts",
],
"kbn_references": [
"@kbn/peggy"
"**/*.js"
],
"exclude": [
"target/**/*",
],
"kbn_references": [
"@kbn/peggy",
]
}

View file

@ -40,9 +40,6 @@ it('builds a generated plugin into a viable archive', async () => {
process.execPath,
['scripts/generate_plugin', '-y', '--name', 'fooTestPlugin'],
{
env: {
NODE_OPTIONS: '--openssl-legacy-provider',
},
cwd: REPO_ROOT,
all: true,
}
@ -55,8 +52,7 @@ it('builds a generated plugin into a viable archive', async () => {
};
expect(filterLogs(generateProc.all)).toMatchInlineSnapshot(`
"Kibana is currently running with legacy OpenSSL providers enabled! For details and instructions on how to disable see https://www.elastic.co/guide/en/kibana/current/production.html#openssl-legacy-provider
succ 🎉
" succ 🎉
Your plugin has been created in plugins/foo_test_plugin
"
@ -66,17 +62,13 @@ it('builds a generated plugin into a viable archive', async () => {
process.execPath,
['../../scripts/plugin_helpers', 'build', '--kibana-version', '7.5.0'],
{
env: {
NODE_OPTIONS: '--openssl-legacy-provider',
},
cwd: PLUGIN_DIR,
all: true,
}
);
expect(filterLogs(buildProc.all)).toMatchInlineSnapshot(`
"Kibana is currently running with legacy OpenSSL providers enabled! For details and instructions on how to disable see https://www.elastic.co/guide/en/kibana/current/production.html#openssl-legacy-provider
info deleting the build and target directories
" info deleting the build and target directories
info run bazel and build required artifacts for the optimizer
succ bazel run successfully and artifacts were created
info running @kbn/optimizer
@ -106,8 +98,8 @@ it('builds a generated plugin into a viable archive', async () => {
"kibana/fooTestPlugin/server/plugin.js",
"kibana/fooTestPlugin/server/routes/index.js",
"kibana/fooTestPlugin/server/types.js",
"kibana/fooTestPlugin/target/public/fooTestPlugin.chunk.1.js",
"kibana/fooTestPlugin/target/public/fooTestPlugin.chunk.1.js.br",
"kibana/fooTestPlugin/target/public/fooTestPlugin.chunk.998.js",
"kibana/fooTestPlugin/target/public/fooTestPlugin.chunk.998.js.br",
"kibana/fooTestPlugin/target/public/fooTestPlugin.plugin.js",
"kibana/fooTestPlugin/target/public/fooTestPlugin.plugin.js.br",
"kibana/fooTestPlugin/translations/ja-JP.json",

View file

@ -64,7 +64,7 @@ export async function optimize({
const proc = fork(require.resolve('./optimize_worker'), {
cwd: REPO_ROOT,
execArgv: ['--require=@kbn/babel-register/install', '--openssl-legacy-provider'],
execArgv: ['--require=@kbn/babel-register/install'],
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
});

View file

@ -42,7 +42,7 @@ process.on('message', (msg: any) => {
return;
}
if (stats.hasErrors()) {
if (stats?.hasErrors()) {
send.call(process, {
success: false,
error: `Failed to compile with webpack:\n${stats.toString()}`,
@ -52,7 +52,7 @@ process.on('message', (msg: any) => {
send.call(process, {
success: true,
warnings: stats.hasWarnings() ? stats.toString() : '',
warnings: stats?.hasWarnings() ? stats.toString() : '',
});
}
);

View file

@ -13,7 +13,7 @@ This package exposes a class which can be used to efficiently classify all of th
- `browser package`: plugin code in the root `public/` directory (and a few others in specific plugins), eventually this will include packages of type `browser-plugin` or `browser-shared`
- `common packages`: includes any existing package, plugin code in root `common/` directories, (and a few others in specific plugins), Eventually this will include `common-shared` packages
- `tests or mocks`: code that is loaded by jest/storybook, and mocks/helpers intended for use by that code. These files usually live along side package code but will have a separate dependency tree and are pieces of code which should never end up in the product.
- `static`: static files, currently any .json file or things loaded via `raw-loader` in browser code
- `static`: static files, currently any .json file or things loaded via `?raw` or `?asUrl` in browser code
- `tooling`: scripts, config files for tools like eslint, webpack, etc.
- `non-package`: code that lives outside of packages/plugins or doesn't fit into other more specific categories. Once the package project is complete this category should be limited to just `@kbn/pm`

View file

@ -12,26 +12,17 @@
// This plugin suppresses the irritating TS-related warnings in Storybook HMR.
import { Compiler, Stats } from 'webpack';
// @ts-expect-error
import ModuleDependencyWarning from 'webpack/lib/ModuleDependencyWarning';
export class IgnoreNotFoundExportPlugin {
apply(compiler: Compiler) {
const messageRegExp = /export '.*'( \(reexported as '.*'\))? was not found in/;
const doneHook = (stats: Stats) =>
(stats.compilation.warnings = stats.compilation.warnings.filter(
(warn: any) =>
// Unfortunately webpack is not exporting ModuleDependencyWarning type, so I'm using constructor.name instead
warn.constructor.name === 'ModuleDependencyWarning' && !messageRegExp.test(warn.message)
));
function doneHook(stats: Stats) {
stats.compilation.warnings = stats.compilation.warnings.filter(function (warn) {
if (warn instanceof ModuleDependencyWarning && messageRegExp.test(warn.message)) {
return false;
}
return true;
});
}
if (compiler.hooks) {
compiler.hooks.done.tap('IgnoreNotFoundExportPlugin', doneHook);
} else {
compiler.plugin('done', doneHook);
}
compiler.hooks.done.tap('IgnoreNotFoundExportPlugin', doneHook);
}
}

View file

@ -11,7 +11,7 @@ import * as path from 'path';
import fs from 'fs';
import type { StorybookConfig } from '@storybook/core-common';
import webpack, { Configuration } from 'webpack';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { REPO_ROOT } from './constants';
import { default as WebpackConfig } from '../webpack.config';
@ -24,11 +24,18 @@ const toPath = (_path: string) => path.join(REPO_ROOT, _path);
// This ignore pattern excludes all of node_modules EXCEPT for `@kbn`. This allows for
// changes to packages to cause a refresh in Storybook.
const IGNORE_PATTERN =
/[/\\]node_modules[/\\](?!@kbn[/\\][^/\\]+[/\\](?!node_modules)([^/\\]+))([^/\\]+[/\\][^/\\]+)/;
const IGNORE_GLOBS = [
'**/node_modules/**',
'!**/node_modules/@kbn/**',
'!**/node_modules/@kbn/*/**',
'!**/node_modules/@kbn/*/!(node_modules)/**',
];
export const defaultConfig: StorybookConfig = {
addons: ['@kbn/storybook/preset', '@storybook/addon-a11y', '@storybook/addon-essentials'],
core: {
builder: 'webpack5',
},
stories: ['../**/*.stories.tsx', '../**/*.stories.mdx'],
typescript: {
reactDocgen: false,
@ -99,11 +106,17 @@ export const defaultConfig: StorybookConfig = {
})
);
config.node = { fs: 'empty' };
config.resolve = {
...config.resolve,
fallback: {
...config?.resolve?.fallback,
fs: false,
},
};
config.watch = true;
config.watchOptions = {
...config.watchOptions,
ignored: [IGNORE_PATTERN],
ignored: IGNORE_GLOBS,
};
// Remove when @storybook has moved to @emotion v11

View file

@ -7,25 +7,18 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
/* eslint-disable import/no-default-export */
import { externals } from '@kbn/ui-shared-deps-src';
import { stringifyRequest } from 'loader-utils';
import { resolve } from 'path';
import webpack, { Configuration, Stats } from 'webpack';
import webpackMerge from 'webpack-merge';
import webpack, { Configuration } from 'webpack';
import { merge as webpackMerge } from 'webpack-merge';
import { NodeLibsBrowserPlugin } from '@kbn/node-libs-browser-webpack-plugin';
import { REPO_ROOT } from './lib/constants';
import { IgnoreNotFoundExportPlugin } from './ignore_not_found_export_plugin';
import 'webpack-dev-server'; // Extends webpack configuration with `devServer` property
type Preset = string | [string, Record<string, unknown>] | Record<string, unknown>;
const stats = {
...Stats.presetToOptions('minimal'),
colors: true,
errorDetails: true,
errors: true,
moduleTrace: true,
};
function isProgressPlugin(plugin: any) {
return 'handler' in plugin && plugin.showActiveModules && plugin.showModules;
}
@ -35,7 +28,10 @@ function isHtmlPlugin(plugin: any): plugin is { options: { template: string } }
}
interface BabelLoaderRule extends webpack.RuleSetRule {
use: webpack.RuleSetLoader[];
use: Array<{
loader: 'babel-loader';
[key: string]: unknown;
}>;
}
function isBabelLoaderRule(rule: webpack.RuleSetRule): rule is BabelLoaderRule {
@ -44,7 +40,7 @@ function isBabelLoaderRule(rule: webpack.RuleSetRule): rule is BabelLoaderRule {
Array.isArray(rule.use) &&
rule.use.some(
(l) =>
typeof l === 'object' && typeof l.loader === 'string' && l.loader.includes('babel-loader')
typeof l === 'object' && typeof l?.loader === 'string' && l?.loader.includes('babel-loader')
)
);
}
@ -69,12 +65,14 @@ function isDesiredPreset(preset: Preset) {
}
// Extend the Storybook Webpack config with some customizations
/* eslint-disable import/no-default-export */
/**
* @returns {import('webpack').Configuration}
*/
export default ({ config: storybookConfig }: { config: Configuration }) => {
const config: Configuration = {
devServer: {
devMiddleware: {
stats,
stats: 'errors-only',
},
},
externals,
@ -91,9 +89,7 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
},
{
test: /\.(html|md|txt|tmpl)$/,
use: {
loader: 'raw-loader',
},
type: 'asset/source',
},
{
test: /\.peggy$/,
@ -119,10 +115,13 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
loader: 'sass-loader',
options: {
additionalData(content: string, loaderContext: any) {
return `@import ${stringifyRequest(
loaderContext,
resolve(REPO_ROOT, 'src/core/public/styles/core_app/_globals_v8light.scss')
)};\n${content}`;
const req = JSON.stringify(
loaderContext.utils.contextify(
loaderContext.context || loaderContext.rootContext,
resolve(REPO_ROOT, 'src/core/public/styles/core_app/_globals_v8light.scss')
)
);
return `@import ${req};\n${content}`;
},
implementation: require('sass-embedded'),
sassOptions: {
@ -133,39 +132,9 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
},
],
},
{
test: /node_modules\/@?xstate5\/.*\.js$/,
use: {
loader: 'babel-loader',
options: {
babelrc: false,
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
plugins: ['@babel/plugin-transform-logical-assignment-operators'],
},
},
},
{
test: /\.js$/,
include: /node_modules[\\\/]@dagrejs/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'], // Doesn't work with @kbn/babel-preset/webpack_preset
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
},
{
test: /node_modules[\/\\]@?xyflow[\/\\].*.js$/,
loaders: 'babel-loader',
options: {
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
plugins: ['@babel/plugin-transform-logical-assignment-operators'],
},
},
],
},
plugins: [new IgnoreNotFoundExportPlugin()],
plugins: [new NodeLibsBrowserPlugin(), new IgnoreNotFoundExportPlugin()],
resolve: {
extensions: ['.js', '.mjs', '.ts', '.tsx', '.json', '.mdx'],
mainFields: ['browser', 'main'],
@ -175,16 +144,16 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
vega: resolve(REPO_ROOT, 'node_modules/vega/build-es5/vega.js'),
},
},
stats,
stats: 'errors-only',
};
// Override storybookConfig mainFields instead of merging with config
delete storybookConfig.resolve?.mainFields;
const updatedModuleRules = [];
const updatedModuleRules: webpack.RuleSetRule[] = [];
// 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 };
const rule = typeof originalRule !== 'string' ? { ...originalRule } : {};
updatedModuleRules.push(rule);
if (isBabelLoaderRule(rule)) {
@ -237,7 +206,7 @@ export default ({ config: storybookConfig }: { config: Configuration }) => {
filteredStorybookPlugins.push(plugin);
}
return webpackMerge(
return webpackMerge<object>(
{
...storybookConfig,
plugins: filteredStorybookPlugins,

View file

@ -22,6 +22,7 @@
"@kbn/core-i18n-browser",
"@kbn/react-kibana-context-root",
"@kbn/core-analytics-browser",
"@kbn/node-libs-browser-webpack-plugin",
],
"exclude": [
"target/**/*",

View file

@ -32,6 +32,18 @@ const STATIC_FILE_EXT =
const IS_REACT_18 = process.env.REACT_18 === 'true';
/**
* @param {string} str
* @returns
*/
function parseRequestOrExtSuffix(str) {
const rawSuffix = '?raw';
if (str.endsWith(rawSuffix)) {
return str.slice(0, -rawSuffix.length);
}
return str;
}
/**
* @param {string} request
* @param {import('resolve').SyncOpts} options
@ -85,25 +97,27 @@ module.exports = (request, options) => {
const reqExt = Path.extname(request);
if (reqExt) {
const reqBasename = Path.basename(request, reqExt);
if ((reqExt === '.css' || reqExt === '.scss') && reqBasename.endsWith('.module')) {
const pRequest = parseRequestOrExtSuffix(request);
const pReqExt = parseRequestOrExtSuffix(reqExt);
const reqBasename = Path.basename(pRequest, pReqExt);
if ((pReqExt === '.css' || pReqExt === '.scss') && reqBasename.endsWith('.module')) {
return CSS_MODULE_MOCK;
}
if (reqExt === '.css' || reqExt === '.less' || reqExt === '.scss') {
if (pReqExt === '.css' || pReqExt === '.less' || pReqExt === '.scss') {
return STYLE_MOCK;
}
if (STATIC_FILE_EXT.includes(reqExt)) {
if (STATIC_FILE_EXT.includes(pReqExt)) {
return FILE_MOCK;
}
if (reqExt === '.worker' && reqBasename.endsWith('.editor')) {
if (pReqExt === '.worker' && reqBasename.endsWith('.editor')) {
return WORKER_MOCK;
}
}
if (request.startsWith('file-loader!') || request.startsWith('!!file-loader!')) {
if (request.endsWith('?asUrl')) {
return FILE_MOCK;
}

View file

@ -42,6 +42,15 @@
],
"enabled": false
},
{
"groupName": "webpack",
"matchDepNames": ["webpack", "@types/webpack", "webpack-cli", "webpack-dev-server", "webpack-merge"],
"reviewers": ["team:kibana-operations"],
"matchBaseBranches": ["main"],
"labels": ["Team:Operations", "backport:all-open", "release_note:skip", "ci:build-webpack-bundle-analyzer"],
"minimumReleaseAge": "60 days",
"enabled": true
},
{
"groupName": "devcontainer",
"reviewers": [
@ -4324,6 +4333,25 @@
"Feature:Console"
],
"enabled": true
},
{
"groupName": "node-libs-browser",
"matchDepNames": [
"node-libs-browser"
],
"reviewers": [
"team:kibana-operations"
],
"matchBaseBranches": [
"main"
],
"labels": [
"Team:Operations",
"backport:prev-minor",
"release_note:skip"
],
"minimumReleaseAge": "7 days",
"enabled": true
}
],
"customManagers": [

View file

@ -9,7 +9,7 @@
import { BehaviorSubject } from 'rxjs';
jest.mock('!!raw-loader!./disable_animations.css', () => 'MOCK DISABLE ANIMATIONS CSS');
jest.mock('./disable_animations.css?raw', () => 'MOCK DISABLE ANIMATIONS CSS');
import { StylesService } from './styles_service';
import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks';

View file

@ -12,7 +12,7 @@ import { Subscription } from 'rxjs';
import type { CoreService } from '@kbn/core-base-browser-internal';
import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
// @ts-expect-error
import disableAnimationsCss from '!!raw-loader!./disable_animations.css';
import disableAnimationsCss from './disable_animations.css?raw';
interface StartDeps {
uiSettings: IUiSettingsClient;

View file

@ -41,6 +41,7 @@ run(
log.verbose('Loading Storybook:', configDir);
// TODO: once storybook is upgraded into a newer version, --no-deprecation flag could be removed when invoking it through the package.json script
runStorybookCli({ configDir, name: alias });
},
{

View file

@ -33,10 +33,8 @@ import type {
// @ts-expect-error
import maplibreglDist from 'maplibre-gl/dist/maplibre-gl-csp';
// @ts-expect-error
import mbRtlPlugin from '!!file-loader!@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js';
// @ts-expect-error
import mbWorkerUrl from '!!file-loader!maplibre-gl/dist/maplibre-gl-csp-worker';
import mbRtlPlugin from '@mapbox/mapbox-gl-rtl-text/mapbox-gl-rtl-text.min.js?asUrl';
import mbWorkerUrl from 'maplibre-gl/dist/maplibre-gl-csp-worker?asUrl';
import 'maplibre-gl/dist/maplibre-gl.css';
const maplibregl: any = maplibreglDist;

View file

@ -2,7 +2,7 @@
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": []
"types": ["@kbn/ambient-ui-types"]
},
"include": [
"**/*.ts",

View file

@ -26,8 +26,8 @@ SRCS = glob(
RUNTIME_DEPS = [
"@npm//babel-loader",
"@npm//@babel/plugin-proposal-optional-chaining",
"@npm//loader-utils",
"@npm//val-loader",
"//packages/kbn-node-libs-browser-webpack-plugin",
"//src/platform/packages/shared/kbn-repo-info",
# deps in the dll need to be included in the sandbox for consumers
# of this DLL (ui-shared-deps-src) because webpack won't actually
@ -53,6 +53,7 @@ RUNTIME_DEPS = [
"@npm//jquery",
"@npm//lodash",
"@npm//moment-timezone",
"@npm//node-libs-browser",
"@npm//react-dom",
"@npm//react-dom-18",
"@npm//react-router-dom",
@ -96,11 +97,9 @@ webpack_cli(
env = select({
"//:dist": {
"NODE_ENV": "production",
"NODE_OPTIONS": "--openssl-legacy-provider",
},
"//conditions:default": {
"NODE_ENV": "development",
"NODE_OPTIONS": "--openssl-legacy-provider",
"REACT_18": "$(REACT_18)",
},
})

View file

@ -7,19 +7,21 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
// eslint-disable-next-line import/no-extraneous-dependencies
const { stringifyRequest } = require('loader-utils');
const VAL_LOADER = require.resolve('val-loader');
const MODULE_CREATOR = require.resolve('./public_path_module_creator');
/**
* @this {any} this
* @this {import('webpack').LoaderContext<any>}
* @param {string} source
*/
module.exports = function (source) {
const options = this.query;
const valOpts = new URLSearchParams({ key: options.key }).toString();
const req = `${VAL_LOADER}?${valOpts}!${MODULE_CREATOR}`;
return `require(${stringifyRequest(this, req)});${source}`;
const req = JSON.stringify(
this.utils.contextify(
this.context || this.rootContext,
`${VAL_LOADER}?${valOpts}!${MODULE_CREATOR}`
)
);
return `require(${req});${source}`;
};

View file

@ -9,6 +9,7 @@
const Path = require('path');
const webpack = require('webpack');
const { NodeLibsBrowserPlugin } = require('@kbn/node-libs-browser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
@ -19,14 +20,11 @@ const WEBPACK_SRC = require.resolve('webpack');
const REPO_ROOT = Path.resolve(__dirname, '..', '..', '..', '..', '..');
/** @returns {import('webpack').Configuration} */
module.exports = (_, argv) => {
const outputPath = argv.outputPath ? Path.resolve(argv.outputPath) : UiSharedDepsNpm.distDir;
return {
node: {
child_process: 'empty',
fs: 'empty',
},
externals: {
module: 'module',
},
@ -63,12 +61,12 @@ module.exports = (_, argv) => {
'@elastic/charts',
'@elastic/eui',
'@elastic/eui/optimize/es/components/provider/nested',
'@elastic/eui/optimize/es/services',
'@elastic/eui/optimize/es/services/format',
'@elastic/eui/optimize/es/services/theme/warning',
'@elastic/eui/dist/eui_theme_amsterdam_light.json',
'@elastic/eui/dist/eui_theme_amsterdam_dark.json',
'@elastic/eui/dist/eui_theme_borealis_light.json',
'@elastic/eui/dist/eui_theme_borealis_dark.json',
'@elastic/eui-theme-borealis',
'@elastic/numeral',
'@emotion/cache',
'@emotion/react',
@ -105,6 +103,7 @@ module.exports = (_, argv) => {
},
context: __dirname,
devtool: 'cheap-source-map',
target: 'web',
output: {
path: outputPath,
filename: '[name].dll.js',
@ -112,7 +111,6 @@ module.exports = (_, argv) => {
devtoolModuleFilenameTemplate: (info) =>
`kbn-ui-shared-deps-npm/${Path.relative(REPO_ROOT, info.absoluteResourcePath)}`,
library: '__kbnSharedDeps_npm__',
futureEmitAssets: true,
},
module: {
@ -148,11 +146,15 @@ module.exports = (_, argv) => {
react: process.env.REACT_18 === 'true' ? 'react-18' : 'react',
},
extensions: ['.js', '.ts'],
mainFields: ['browser', 'module', 'main'],
conditionNames: ['browser', 'module', 'import', 'require', 'default'],
},
optimization: {
moduleIds: process.env.NODE_ENV === 'production' ? 'deterministic' : 'natural',
chunkIds: process.env.NODE_ENV === 'production' ? 'deterministic' : 'natural',
minimize: false,
noEmitOnErrors: true,
emitOnErrors: false,
},
performance: {
@ -163,6 +165,7 @@ module.exports = (_, argv) => {
},
plugins: [
new NodeLibsBrowserPlugin(),
new CleanWebpackPlugin({
protectWebpackAssets: false,
cleanAfterEveryBuildPatterns: [
@ -175,6 +178,7 @@ module.exports = (_, argv) => {
}),
new webpack.DllPlugin({
context: REPO_ROOT,
entryOnly: false,
path: Path.resolve(outputPath, '[name]-manifest.json'),
name: '__kbnSharedDeps_npm__',
}),

View file

@ -15,7 +15,6 @@ webpack_cli(
"@npm//moment",
"@npm//babel-loader",
"@npm//css-loader",
"@npm//url-loader",
"@npm//@babel/plugin-transform-numeric-separator",
"//src/platform/packages/private/kbn-ui-shared-deps-npm",
"//packages/kbn-babel-register",
@ -57,11 +56,9 @@ webpack_cli(
env = select({
"//:dist": {
"NODE_ENV": "production",
"NODE_OPTIONS": "--openssl-legacy-provider",
},
"//conditions:default": {
"NODE_ENV": "development",
"NODE_OPTIONS": "--openssl-legacy-provider",
"REACT_18": "$(REACT_18)",
},
}),

View file

@ -75,8 +75,7 @@ const externals = {
'@elastic/eui': '__kbnSharedDeps__.ElasticEui',
'@elastic/eui/lib/components/provider/nested':
'__kbnSharedDeps__.ElasticEuiLibComponentsUseIsNestedEuiProvider',
'@elastic/eui/lib/services': '__kbnSharedDeps__.ElasticEuiLibServices',
'@elastic/eui/lib/services/format': '__kbnSharedDeps__.ElasticEuiLibServicesFormat',
'@elastic/eui/lib/services/theme/warning': '__kbnSharedDeps__.ElasticEuiLibServicesThemeWarning',
'@elastic/eui-theme-borealis': '__kbnSharedDeps__.ElasticEuiThemeBorealis',
// transient dep of eui

View file

@ -51,10 +51,9 @@ export const Rxjs = require('rxjs');
export const ElasticNumeral = require('@elastic/numeral');
export const ElasticCharts = require('@elastic/charts');
export const ElasticEui = require('@elastic/eui');
export const ElasticEuiThemeBorealis = require('@elastic/eui-theme-borealis');
export const ElasticEuiLibComponentsUseIsNestedEuiProvider = require('@elastic/eui/optimize/es/components/provider/nested');
export const ElasticEuiLibServices = require('@elastic/eui/optimize/es/services');
export const ElasticEuiLibServicesFormat = require('@elastic/eui/optimize/es/services/format');
export const ElasticEuiLibServicesThemeWarning = require('@elastic/eui/optimize/es/services/theme/warning');
export const ElasticEuiThemeBorealis = require('@elastic/eui-theme-borealis');
export const KbnDatemath = require('@kbn/datemath');
export const HelloPangeaDnd = require('@hello-pangea/dnd/dist/dnd');
export const ReduxjsToolkit = require('@reduxjs/toolkit');

View file

@ -13,6 +13,7 @@ require('@kbn/babel-register').install();
const Path = require('path');
const webpack = require('webpack');
const { NodeLibsBrowserPlugin } = require('@kbn/node-libs-browser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UiSharedDepsNpm = require('@kbn/ui-shared-deps-npm');
@ -22,11 +23,8 @@ const MOMENT_SRC = require.resolve('moment/min/moment-with-locales.js');
const REPO_ROOT = Path.resolve(__dirname, '..', '..', '..', '..', '..');
/** @returns {import('webpack').Configuration} */
module.exports = {
node: {
child_process: 'empty',
fs: 'empty',
},
externals: {
module: 'module',
},
@ -36,6 +34,7 @@ module.exports = {
},
context: __dirname,
devtool: 'cheap-source-map',
target: 'web',
output: {
path: UiSharedDepsSrcDistDir,
filename: '[name].js',
@ -44,7 +43,6 @@ module.exports = {
devtoolModuleFilenameTemplate: (info) =>
`kbn-ui-shared-deps-src/${Path.relative(REPO_ROOT, info.absoluteResourcePath)}`,
library: '__kbnSharedDeps__',
futureEmitAssets: true,
},
module: {
@ -68,13 +66,6 @@ module.exports = {
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.(ttf)(\?|$)/,
loader: 'url-loader',
options: {
limit: 8192,
},
},
{
test: /\.(js|tsx?)$/,
exclude: /[\/\\]node_modules[\/\\](?!@kbn)([^\/\\]+)[\/\\]/,
@ -102,13 +93,28 @@ module.exports = {
},
},
},
// automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using url-loader with asset size limit.
{
test: /\.(ttf)(\?|$)/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8192,
},
},
},
],
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
mainFields: ['browser', 'module', 'main'],
conditionNames: ['browser', 'module', 'import', 'require', 'default'],
alias: {
'@elastic/eui$': '@elastic/eui/optimize/es',
'@elastic/eui/lib/components/provider/nested$':
'@elastic/eui/optimize/es/components/provider/nested',
'@elastic/eui/lib/services/theme/warning$': '@elastic/eui/optimize/es/services/theme/warning',
moment: MOMENT_SRC,
// NOTE: Used to include react profiling on bundles
// https://gist.github.com/bvaughn/25e6233aeb1b4f0cdb8d8366e54a3977#webpack-4
@ -120,8 +126,10 @@ module.exports = {
},
optimization: {
moduleIds: process.env.NODE_ENV === 'production' ? 'deterministic' : 'natural',
chunkIds: process.env.NODE_ENV === 'production' ? 'deterministic' : 'natural',
minimize: false,
noEmitOnErrors: true,
emitOnErrors: false,
},
performance: {
@ -132,6 +140,7 @@ module.exports = {
},
plugins: [
new NodeLibsBrowserPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
}),

View file

@ -28,6 +28,7 @@ SHARED_DEPS = [
"//src/platform/packages/shared/kbn-ui-theme",
"//src/platform/packages/shared/kbn-esql-validation-autocomplete",
"//src/platform/packages/shared/kbn-esql-ast",
"//packages/kbn-node-libs-browser-webpack-plugin",
"@npm//antlr4",
"@npm//monaco-editor",
"@npm//monaco-yaml",
@ -41,7 +42,6 @@ webpack_cli(
"@npm//terser-webpack-plugin",
"@npm//@babel/runtime",
"@npm//babel-loader",
"@npm//raw-loader",
"@npm//rxjs",
"webpack.config.js",
@ -59,11 +59,9 @@ webpack_cli(
env = select({
"//:dist": {
"NODE_ENV": "production",
"NODE_OPTIONS": "--openssl-legacy-provider",
},
"//conditions:default": {
"NODE_ENV": "development",
"NODE_OPTIONS": "--openssl-legacy-provider",
},
}),
visibility = ["//visibility:public"],

View file

@ -8,6 +8,7 @@
*/
const path = require('path');
const { NodeLibsBrowserPlugin } = require('@kbn/node-libs-browser-webpack-plugin');
const getWorkerEntry = (language) => {
switch (language) {
@ -30,7 +31,8 @@ const workerConfig = (languages) => ({
entries[language] = getWorkerEntry(language);
return entries;
}, {}),
devtool: process.env.NODE_ENV === 'production' ? false : '#cheap-source-map',
devtool: process.env.NODE_ENV === 'production' ? false : 'cheap-source-map',
target: 'web',
output: {
path: path.resolve(__dirname, 'target_workers'),
filename: ({ chunk }) => `${chunk.name}.editor.worker.js`,
@ -42,6 +44,7 @@ const workerConfig = (languages) => ({
'vscode-uri$': require.resolve('vscode-uri').replace(/\/umd\/index.js/, '/esm/index.mjs'),
},
},
plugins: [new NodeLibsBrowserPlugin()],
stats: 'errors-only',
module: {
rules: [

View file

@ -8,6 +8,6 @@
*/
// @ts-ignore
import defaultSpec from '!!raw-loader!./default.spec.hjson';
import defaultSpec from './default.spec.hjson?raw';
export const getDefaultSpec = () => defaultSpec;

View file

@ -8,7 +8,7 @@
*/
import { defaultConfig } from '@kbn/storybook';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { resolve } from 'path';
const mockConfig = {

View file

@ -8,7 +8,7 @@
*/
import { defaultConfig } from '@kbn/storybook';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { resolve } from 'path';
const mockConfig = {

View file

@ -8,7 +8,7 @@
*/
import { defaultConfig } from '@kbn/storybook';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { resolve } from 'path';
const mockConfig = {

View file

@ -1,4 +1,4 @@
@import 'src/core/public/mixins';
@import '../../../../../../../src/core/public/mixins';
.dshUnsavedListingItem {
margin-top: $euiSizeM;

View file

@ -7,9 +7,9 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { defaultConfig, StorybookConfig } from '@kbn/storybook';
import { defaultConfig } from '@kbn/storybook';
export const discoverStorybookConfig: StorybookConfig = {
module.exports = {
...defaultConfig,
stories: ['../**/*.stories.tsx'],
};

View file

@ -8,7 +8,7 @@
*/
import { defaultConfig } from '@kbn/storybook';
import webpackMerge from 'webpack-merge';
import { merge as webpackMerge } from 'webpack-merge';
import { resolve } from 'path';
const mockConfig = {

View file

@ -1324,6 +1324,8 @@
"@kbn/newsfeed-test-plugin/*": ["test/common/plugins/newsfeed/*"],
"@kbn/no-data-page-plugin": ["src/platform/plugins/private/no_data_page"],
"@kbn/no-data-page-plugin/*": ["src/platform/plugins/private/no_data_page/*"],
"@kbn/node-libs-browser-webpack-plugin": ["packages/kbn-node-libs-browser-webpack-plugin"],
"@kbn/node-libs-browser-webpack-plugin/*": ["packages/kbn-node-libs-browser-webpack-plugin/*"],
"@kbn/notifications-plugin": ["x-pack/platform/plugins/shared/notifications"],
"@kbn/notifications-plugin/*": ["x-pack/platform/plugins/shared/notifications/*"],
"@kbn/object-utils": ["src/platform/packages/shared/kbn-object-utils"],

View file

@ -55,7 +55,6 @@ run(
execa.sync(
process.execPath,
[
'--openssl-legacy-provider',
require.resolve('webpack-dev-server/bin/webpack-dev-server'),
'--config',
webpackConfig,
@ -89,7 +88,6 @@ run(
execa.sync(
process.execPath,
[
'--openssl-legacy-provider',
require.resolve('webpack/bin/webpack'),
'--config',
webpackConfig,

View file

@ -18,9 +18,10 @@
}
:global .kbnCanvas :local .slideContainer {
@include euiScrollBar;
display: flex;
overflow-x: auto;
overflow-y: hidden;
width: 100%;
@include euiScrollBar;
}

View file

@ -9,7 +9,6 @@ require('@kbn/babel-register').install();
const path = require('path');
const webpack = require('webpack');
const { stringifyRequest } = require('loader-utils');
const { CiStatsPlugin } = require('./webpack/ci_stats_plugin');
const {
@ -21,11 +20,13 @@ const {
const isProd = process.env.NODE_ENV === 'production';
/** @type {import('webpack').Configuration} */
module.exports = {
context: KIBANA_ROOT,
entry: {
[SHAREABLE_RUNTIME_NAME]: require.resolve('./index.ts'),
},
target: 'web',
mode: isProd ? 'production' : 'development',
output: {
path: SHAREABLE_RUNTIME_OUTPUT,
@ -35,18 +36,28 @@ module.exports = {
resolve: {
alias: {
core_app_image_assets: path.resolve(KIBANA_ROOT, 'src/core/public/styles/core_app/images'),
[require.resolve('@elastic/eui/es/components/drag_and_drop')]: false,
},
extensions: ['.js', '.json', '.ts', '.tsx', '.scss'],
mainFields: ['browser', 'main'],
mainFields: ['browser', 'module', 'main'],
fallback: {
fs: false,
child_process: false,
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: 'babel-loader',
loader: 'babel-loader',
options: {
presets: [require.resolve('@kbn/babel-preset/webpack_preset')],
presets: [
[
require.resolve('@kbn/babel-preset/webpack_preset'),
{ useTransformRequireDefault: true },
],
],
},
},
{
@ -105,15 +116,15 @@ module.exports = {
},
{
test: /\.module\.s(a|c)ss$/,
loader: [
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]',
exportLocalsConvention: 'camelCase',
},
localsConvention: 'camelCase',
sourceMap: !isProd,
},
},
@ -160,10 +171,16 @@ module.exports = {
loader: 'sass-loader',
options: {
additionalData(content, loaderContext) {
return `@import ${stringifyRequest(
loaderContext,
path.resolve(KIBANA_ROOT, 'src/core/public/styles/core_app/_globals_v8light.scss')
)};\n${content}`;
const req = JSON.stringify(
loaderContext.utils.contextify(
loaderContext.context || loaderContext.rootContext,
path.resolve(
KIBANA_ROOT,
'src/core/public/styles/core_app/_globals_v8light.scss'
)
)
);
return `@import ${req};\n${content}`;
},
implementation: require('sass-embedded'),
sassOptions: {
@ -176,11 +193,23 @@ module.exports = {
},
{
test: require.resolve('jquery'),
loader: 'expose-loader?jQuery!expose-loader?$',
use: [
{
loader: 'expose-loader',
options: {
exposes: ['jQuery', '$'],
},
},
],
},
{
test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/,
loader: 'url-loader',
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8192,
},
},
sideEffects: false,
},
{
@ -188,20 +217,12 @@ module.exports = {
loader: 'html-loader',
exclude: /node_modules/,
},
{
test: [require.resolve('@elastic/eui/es/components/drag_and_drop')],
use: require.resolve('null-loader'),
},
{
test: /\.peggy$/,
use: require.resolve('@kbn/peggy-loader'),
},
],
},
node: {
fs: 'empty',
child_process: 'empty',
},
plugins: [
isProd ? new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }) : [],
new CiStatsPlugin({

View file

@ -67,7 +67,7 @@ export class CiStatsPlugin {
throw new Error(`Unable to find bundle entry named [${entryName}]`);
}
const moduleCount = compilation.modules.reduce((acc, module) => {
const moduleCount = Array.from(compilation.modules).reduce((acc, module) => {
if (isNormalModule(module)) {
return acc + 1;
}

View file

@ -8,15 +8,16 @@
import { resolve } from 'path';
import { defaultConfig, mergeWebpackFinal } from '@kbn/storybook';
import type { StorybookConfig } from '@kbn/storybook';
import { Configuration } from 'webpack';
import { KIBANA_ROOT } from './constants';
export const canvasWebpack = {
export const canvasWebpack: Configuration = {
module: {
rules: [
// Enable CSS Modules in Storybook (Shareable Runtime)
{
test: /\.module\.s(a|c)ss$/,
loader: [
use: [
'style-loader',
{
loader: 'css-loader',
@ -39,26 +40,21 @@ export const canvasWebpack = {
loader: 'sass-loader',
options: {
implementation: require('sass-embedded'),
sassOptions: {
quietDeps: true,
},
},
},
],
},
// Exclude large-dependency, troublesome or irrelevant modules.
{
test: [
resolve(
KIBANA_ROOT,
'x-pack/platform/plugins/private/canvas/public/components/embeddable_flyout'
),
resolve(KIBANA_ROOT, 'x-pack/platform/plugins/private/reporting/public'),
],
use: 'null-loader',
},
],
},
resolve: {
alias: {
'src/plugins': resolve(KIBANA_ROOT, 'src/plugins'),
// Exclude large-dependency, troublesome or irrelevant modules.
[resolve(KIBANA_ROOT, 'x-pack/plugins/canvas/public/components/embeddable_flyout')]: false,
[resolve(KIBANA_ROOT, 'x-pack/plugins/reporting/public')]: false,
},
},
};

View file

@ -5,11 +5,11 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress_space_awareness": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../x-pack/solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/fleet/cypress.config.space_awareness.ts --ftr-config-file ../../../../../x-pack/test/fleet_cypress/cli_config.space_awareness",
"cypress_space_awareness": "node ../../../../../x-pack/solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/fleet/cypress.config.space_awareness.ts --ftr-config-file ../../../../../x-pack/test/fleet_cypress/cli_config.space_awareness",
"cypress_space_awareness:open": "yarn cypress_space_awareness open",
"cypress_space_awareness:run": "yarn cypress_space_awareness run",
"cypress_space_awareness:run:reporter": "yarn cypress_space_awareness run --reporter ../../../../../node_modules/cypress-multi-reporters --reporter-options configFile=cypress/reporter_config.json",
"cypress": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../x-pack/solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/fleet/cypress.config.ts --ftr-config-file ../../../../../x-pack/test/fleet_cypress/cli_config",
"cypress": "node ../../../../../x-pack/solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/fleet/cypress.config.ts --ftr-config-file ../../../../../x-pack/test/fleet_cypress/cli_config",
"cypress:open": "yarn cypress open",
"cypress:run": "yarn cypress run",
"cypress:run:reporter": "yarn cypress run --reporter ../../../../../node_modules/cypress-multi-reporters --reporter-options configFile=cypress/reporter_config.json",

View file

@ -8,7 +8,7 @@
import { EuiPageTemplate } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import React from 'react';
import { css } from '@emotion/react/dist/emotion-react.cjs';
import { css } from '@emotion/react';
export const EmptyList = ({ addDatabaseButton }: { addDatabaseButton: JSX.Element }) => {
return (

View file

@ -7,13 +7,13 @@
"scripts": {
"cypress:burn": "yarn cypress:run --env burn=2 --headed",
"cypress:changed-specs-only": "yarn cypress:run --changed-specs-only --env burn=2",
"cypress": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/cypress.config.ts --ftr-config-file ../../../../../x-pack/test/osquery_cypress/cli_config",
"cypress": "node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/cypress.config.ts --ftr-config-file ../../../../../x-pack/test/osquery_cypress/cli_config",
"cypress:open": "yarn cypress open",
"cypress:run": "yarn cypress run",
"cypress:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/serverless_cypress.config.ts --ftr-config-file ../../../../../x-pack/test/osquery_cypress/serverless_cli_config",
"cypress:serverless": "node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/serverless_cypress.config.ts --ftr-config-file ../../../../../x-pack/test/osquery_cypress/serverless_cli_config",
"cypress:serverless:open": "yarn cypress:serverless open",
"cypress:serverless:run": "yarn cypress:serverless run",
"cypress:qa:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel_serverless --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/serverless_cypress_qa.config.ts --onBeforeHook ../../../../test/osquery_cypress/runner_qa.ts",
"cypress:qa:serverless": "node ../../../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel_serverless --config-file ../../../x-pack/platform/plugins/shared/osquery/cypress/serverless_cypress_qa.config.ts --onBeforeHook ../../../../test/osquery_cypress/runner_qa.ts",
"cypress:qa:serverless:run": "yarn cypress:qa:serverless run",
"nyc": "../../../../../node_modules/.bin/nyc report --reporter=text-summary",
"junit:merge": "../../../../../node_modules/.bin/mochawesome-merge ../../../../../target/kibana-osquery/cypress/results/mochawesome*.json > ../../../../../target/kibana-osquery/cypress/results/output.json && ../../../../../node_modules/.bin/marge ../../../../../target/kibana-osquery/cypress/results/output.json --reportDir ../../../../../target/kibana-osquery/cypress/results && yarn junit:transform && mkdir -p ../../../../../target/junit && cp ../../../../../target/kibana-osquery/cypress/results/*.xml ../../../../../target/junit/",
@ -21,4 +21,4 @@
"openapi:generate": "node scripts/openapi/generate",
"openapi:bundle": "node scripts/openapi/bundle"
}
}
}

View file

@ -5,7 +5,7 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../observability/plugins/apm/ftr_e2e/cypress.config.ts --ftr-config-file ../../../../../test/apm_cypress/cli_config",
"cypress": "node ../../../../security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../observability/plugins/apm/ftr_e2e/cypress.config.ts --ftr-config-file ../../../../../test/apm_cypress/cli_config",
"cypress:open": "yarn cypress open",
"cypress:run": "yarn cypress run",
"cypress:run:headed": "yarn cypress run --headed",

View file

@ -73,7 +73,6 @@ function runTests() {
env: {
...process.env,
CYPRESS_CLI_ARGS: JSON.stringify(cypressCliArgs),
NODE_OPTIONS: '--openssl-legacy-provider',
},
encoding: 'utf8',
stdio: 'inherit',

View file

@ -80,7 +80,6 @@ function runTests() {
env: {
...process.env,
CYPRESS_CLI_ARGS: JSON.stringify(cypressCliArgs),
NODE_OPTIONS: '--openssl-legacy-provider',
},
encoding: 'utf8',
stdio: 'inherit',

View file

@ -5,7 +5,7 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../observability/plugins/profiling/e2e/cypress.config.ts --ftr-config-file ../../../../../test/profiling_cypress/cli_config",
"cypress": "node ../../../../security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../observability/plugins/profiling/e2e/cypress.config.ts --ftr-config-file ../../../../../test/profiling_cypress/cli_config",
"cypress:open": "yarn cypress open",
"cypress:run": "yarn cypress run",
"cypress:run:headed": "yarn cypress run --headed",

View file

@ -18,11 +18,11 @@ const graphWebpack: Configuration = {
'../src/components/mock/use_fetch_graph_data.mock.ts'
),
},
},
node: {
fs: 'empty',
stream: false,
os: false,
fallback: {
fs: false,
stream: false,
os: false,
},
},
};

View file

@ -7,16 +7,16 @@
"scripts": {
"extract-mitre-attacks": "node scripts/extract_tactics_techniques_mitre.js && node ../../../../../scripts/eslint ./public/detections/mitre/mitre_tactics_techniques.ts --fix",
"build-beat-doc": "node scripts/beat_docs/build.js && node ../../../../../scripts/eslint ../timelines/server/utils/beat_schema/fields.ts --fix",
"cypress": "NODE_OPTIONS=--openssl-legacy-provider ../../../../../node_modules/.bin/cypress",
"cypress": "../../../../../node_modules/.bin/cypress",
"cypress:burn": "yarn cypress:dw run --env burn=2 --headed",
"cypress:changed-specs-only": "yarn cypress:dw run --changed-specs-only --env burn=2",
"cypress:dw": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel --config-file plugins/security_solution/public/management/cypress/cypress.config.ts --ftr-config-file ../../../../test/defend_workflows_cypress/cli_config",
"cypress:dw": "node ./scripts/start_cypress_parallel --config-file plugins/security_solution/public/management/cypress/cypress.config.ts --ftr-config-file ../../../../test/defend_workflows_cypress/cli_config",
"cypress:dw:open": "yarn cypress:dw open",
"cypress:dw:run": "yarn cypress:dw run",
"cypress:dw:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel --config-file plugins/security_solution/public/management/cypress/cypress_serverless.config.ts --ftr-config-file ../../../../test/defend_workflows_cypress/serverless_config",
"cypress:dw:serverless": "node ./scripts/start_cypress_parallel --config-file plugins/security_solution/public/management/cypress/cypress_serverless.config.ts --ftr-config-file ../../../../test/defend_workflows_cypress/serverless_config",
"cypress:dw:serverless:open": "yarn cypress:dw:serverless open",
"cypress:dw:serverless:run": "yarn cypress:dw:serverless run",
"cypress:dw:qa:serverless": "NODE_OPTIONS=--openssl-legacy-provider node ./scripts/start_cypress_parallel_serverless --config-file plugins/security_solution/public/management/cypress/cypress_serverless_qa.config.ts",
"cypress:dw:qa:serverless": "node ./scripts/start_cypress_parallel_serverless --config-file plugins/security_solution/public/management/cypress/cypress_serverless_qa.config.ts",
"cypress:dw:qa:serverless:run": "yarn cypress:dw:qa:serverless run",
"cypress:dw:serverless:changed-specs-only": "yarn cypress:dw:serverless run --changed-specs-only --env burn=2",
"cypress:dw:endpoint": "echo '\n** WARNING **: Run script `cypress:dw:endpoint` no longer valid! Use `cypress:dw` instead\n'",

View file

@ -5,12 +5,12 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress": "NODE_OPTIONS=--openssl-legacy-provider ../../../node_modules/.bin/cypress",
"cypress:open:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../test/security_solution_cypress/cypress/cypress.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
"cypress": "../../../node_modules/.bin/cypress",
"cypress:open:ess": "TZ=UTC node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel open --spec './cypress/e2e/**/*.cy.ts' --config-file ../../test/security_solution_cypress/cypress/cypress.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
"cypress:asset_inventory:run:ess": "yarn cypress:ess --spec './cypress/e2e/asset_inventory/**/*.cy.ts'",
"cypress:entity_analytics:run:ess": "yarn cypress:ess --spec './cypress/e2e/entity_analytics/**/*.cy.ts'",
"cypress:run:cases:ess": "yarn cypress:ess --spec './cypress/e2e/explore/cases/*.cy.ts'",
"cypress:ess": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel run --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
"cypress:ess": "TZ=UTC node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel run --config-file ../../test/security_solution_cypress/cypress/cypress_ci.config.ts --ftr-config-file ../../test/security_solution_cypress/cli_config",
"cypress:rule_management:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/rule_management/!(prebuilt_rules)/**/*.cy.ts'",
"cypress:rule_management:prebuilt_rules:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/rule_management/prebuilt_rules/**/*.cy.ts'",
"cypress:detection_engine:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/detection_engine/!(exceptions)/**/*.cy.ts'",
@ -24,8 +24,8 @@
"cypress:burn:ess": "yarn cypress:ess --env burn=5",
"junit:merge": "../../../node_modules/.bin/mochawesome-merge ../../../target/kibana-security-solution/cypress/results/mochawesome*.json > ../../../target/kibana-security-solution/cypress/results/output.json && ../../../node_modules/.bin/marge ../../../target/kibana-security-solution/cypress/results/output.json --reportDir ../../../target/kibana-security-solution/cypress/results && yarn junit:transform && mkdir -p ../../../target/junit && cp ../../../target/kibana-security-solution/cypress/results/*.xml ../../../target/junit/",
"junit:transform": "node ../../solutions/security/plugins/security_solution/scripts/junit_transformer --pathPattern '../../../target/kibana-security-solution/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Security Solution Cypress' --writeInPlace",
"cypress:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts --ftr-config-file ../../test/security_solution_cypress/serverless_config",
"cypress:cloud:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider NODE_TLS_REJECT_UNAUTHORIZED=0 ../../../node_modules/.bin/cypress",
"cypress:serverless": "TZ=UTC node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless.config.ts --ftr-config-file ../../test/security_solution_cypress/serverless_config",
"cypress:cloud:serverless": "TZ=UTC NODE_TLS_REJECT_UNAUTHORIZED=0 ../../../node_modules/.bin/cypress",
"cypress:open:cloud:serverless": "yarn cypress:cloud:serverless open --config-file ./cypress/cypress_serverless.config.ts --env CLOUD_SERVERLESS=true",
"cypress:open:serverless": "yarn cypress:serverless open --config-file ../../test/security_solution_cypress/cypress/cypress_serverless.config.ts --spec './cypress/e2e/**/*.cy.ts'",
"cypress:entity_analytics:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/entity_analytics/**/*.cy.ts'",
@ -40,7 +40,7 @@
"cypress:changed-specs-only:serverless": "yarn cypress:serverless --changed-specs-only --env burn=5",
"cypress:cloud_security_posture:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts'",
"cypress:burn:serverless": "yarn cypress:serverless --env burn=2",
"cypress:qa:serverless": "TZ=UTC NODE_OPTIONS=--openssl-legacy-provider node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel_serverless --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts",
"cypress:qa:serverless": "TZ=UTC node ../../solutions/security/plugins/security_solution/scripts/start_cypress_parallel_serverless --config-file ../../test/security_solution_cypress/cypress/cypress_ci_serverless_qa.config.ts",
"cypress:open:qa:serverless": "yarn cypress:qa:serverless open",
"cypress:run:qa:serverless:entity_analytics": "yarn cypress:qa:serverless --spec './cypress/e2e/entity_analytics/**/*.cy.ts'",
"cypress:run:qa:serverless:investigations": "yarn cypress:qa:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'",
@ -52,4 +52,4 @@
"cypress:run:qa:serverless:ai_assistant": "yarn cypress:qa:serverless --spec './cypress/e2e/ai_assistant/**/*.cy.ts'",
"cypress:run:qa:serverless:cloud_security_posture": "yarn cypress:qa:serverless --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts"
}
}
}

View file

@ -5,9 +5,9 @@
"private": true,
"license": "Elastic License 2.0",
"scripts": {
"cypress:open": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../../node_modules/.bin/cypress open --config-file ./cypress.config.ts",
"cypress:run": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../../node_modules/.bin/cypress run --browser chrome --config-file ./cypress.config.ts",
"cypress:serverless:open": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../../scripts/functional_tests --config ./config_runner.ts",
"cypress:serverless:run": "NODE_OPTIONS=--openssl-legacy-provider node ../../../../../../scripts/functional_tests --config ./config_server.ts"
"cypress:open": "node ../../../../../../node_modules/.bin/cypress open --config-file ./cypress.config.ts",
"cypress:run": "node ../../../../../../node_modules/.bin/cypress run --browser chrome --config-file ./cypress.config.ts",
"cypress:serverless:open": "node ../../../../../../scripts/functional_tests --config ./config_runner.ts",
"cypress:serverless:run": "node ../../../../../../scripts/functional_tests --config ./config_server.ts"
}
}

1125
yarn.lock

File diff suppressed because it is too large Load diff