[7.x] Use runtime publicPath for KP plugin bundles (#64226) (#64327)

This commit is contained in:
Josh Dover 2020-04-23 16:03:27 -06:00 committed by GitHub
parent 2a7af585cf
commit c42a2d09a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 132 additions and 40 deletions

File diff suppressed because one or more lines are too long

View file

@ -32,7 +32,6 @@ import * as UiSharedDeps from '@kbn/ui-shared-deps';
import { Bundle, WorkerConfig, parseDirPath, DisallowedSyntaxPlugin } from '../common'; import { Bundle, WorkerConfig, parseDirPath, DisallowedSyntaxPlugin } from '../common';
const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__';
const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset');
const STATIC_BUNDLE_PLUGINS = [ const STATIC_BUNDLE_PLUGINS = [
@ -103,7 +102,6 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
output: { output: {
path: bundle.outputDir, path: bundle.outputDir,
filename: `[name].${bundle.type}.js`, filename: `[name].${bundle.type}.js`,
publicPath: PUBLIC_PATH_PLACEHOLDER,
devtoolModuleFilenameTemplate: info => devtoolModuleFilenameTemplate: info =>
`/${bundle.type}:${bundle.id}/${Path.relative( `/${bundle.type}:${bundle.id}/${Path.relative(
bundle.sourceRoot, bundle.sourceRoot,
@ -144,6 +142,13 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) {
], ],
rules: [ rules: [
{
include: Path.join(bundle.contextDir, bundle.entry),
loader: UiSharedDeps.publicPathLoader,
options: {
key: bundle.id,
},
},
{ {
test: /\.css$/, test: /\.css$/,
include: /node_modules/, include: /node_modules/,

View file

@ -53,3 +53,8 @@ export const lightCssDistFilename: string;
export const externals: { export const externals: {
[key: string]: string; [key: string]: string;
}; };
/**
* Webpack loader for configuring the public path lookup from `window.__kbnPublicPath__`.
*/
export const publicPathLoader: string;

View file

@ -64,3 +64,4 @@ exports.externals = {
'elasticsearch-browser': '__kbnSharedDeps__.ElasticsearchBrowser', 'elasticsearch-browser': '__kbnSharedDeps__.ElasticsearchBrowser',
'elasticsearch-browser/elasticsearch': '__kbnSharedDeps__.ElasticsearchBrowser', 'elasticsearch-browser/elasticsearch': '__kbnSharedDeps__.ElasticsearchBrowser',
}; };
exports.publicPathLoader = require.resolve('./public_path_loader');

View file

@ -0,0 +1,23 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
module.exports = function(source) {
const options = this.query;
return `__webpack_public_path__ = window.__kbnPublicPath__['${options.key}'];${source}`;
};

View file

@ -46,7 +46,6 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({
path: UiSharedDeps.distDir, path: UiSharedDeps.distDir,
filename: '[name].js', filename: '[name].js',
sourceMapFilename: '[file].map', sourceMapFilename: '[file].map',
publicPath: '__REPLACE_WITH_PUBLIC_PATH__',
devtoolModuleFilenameTemplate: info => devtoolModuleFilenameTemplate: info =>
`kbn-ui-shared-deps/${Path.relative(REPO_ROOT, info.absoluteResourcePath)}`, `kbn-ui-shared-deps/${Path.relative(REPO_ROOT, info.absoluteResourcePath)}`,
library: '__kbnSharedDeps__', library: '__kbnSharedDeps__',
@ -55,6 +54,17 @@ exports.getWebpackConfig = ({ dev = false } = {}) => ({
module: { module: {
noParse: [MOMENT_SRC], noParse: [MOMENT_SRC],
rules: [ rules: [
{
include: [require.resolve('./entry.js')],
use: [
{
loader: UiSharedDeps.publicPathLoader,
options: {
key: 'kbn-ui-shared-deps',
},
},
],
},
{ {
test: /\.css$/, test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'], use: [MiniCssExtractPlugin.loader, 'css-loader'],

View file

@ -148,6 +148,19 @@ export default kibana => {
.type('text/css'); .type('text/css');
}, },
}); });
// Sets global variables normally set by the bootstrap.js script
kbnServer.server.route({
path: '/test_bundle/karma/globals.js',
method: 'GET',
async handler(req, h) {
const basePath = config.get('server.basePath');
const file = `window.__kbnPublicPath__ = { 'kbn-ui-shared-deps': "${basePath}/bundles/kbn-ui-shared-deps/" };`;
return h.response(file).header('content-type', 'application/json');
},
});
}, },
__globalImportAliases__: { __globalImportAliases__: {

View file

@ -1,6 +1,7 @@
var kbnCsp = JSON.parse(document.querySelector('kbn-csp').getAttribute('data')); var kbnCsp = JSON.parse(document.querySelector('kbn-csp').getAttribute('data'));
window.__kbnStrictCsp__ = kbnCsp.strictCsp; window.__kbnStrictCsp__ = kbnCsp.strictCsp;
window.__kbnDarkMode__ = {{darkMode}}; window.__kbnDarkMode__ = {{darkMode}};
window.__kbnPublicPath__ = {{publicPathMap}};
if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) {
var legacyBrowserError = document.getElementById('kbn_legacy_browser_error'); var legacyBrowserError = document.getElementById('kbn_legacy_browser_error');

View file

@ -153,11 +153,25 @@ export function uiRenderMixin(kbnServer, server, config) {
`${regularBundlePath}/plugin/kibanaReact/kibanaReact.plugin.js`, `${regularBundlePath}/plugin/kibanaReact/kibanaReact.plugin.js`,
]; ];
const uiPluginIds = [...kbnServer.newPlatform.__internals.uiPlugins.public.keys()];
// These paths should align with the bundle routes configured in
// src/optimize/bundles_route/bundles_route.js
const publicPathMap = JSON.stringify({
core: `${regularBundlePath}/core/`,
'kbn-ui-shared-deps': `${regularBundlePath}/kbn-ui-shared-deps/`,
...uiPluginIds.reduce(
(acc, pluginId) => ({ ...acc, [pluginId]: `${regularBundlePath}/plugin/${pluginId}/` }),
{}
),
});
const bootstrap = new AppBootstrap({ const bootstrap = new AppBootstrap({
templateData: { templateData: {
darkMode, darkMode,
jsDependencyPaths, jsDependencyPaths,
styleSheetPaths, styleSheetPaths,
publicPathMap,
entryBundlePath: isCore entryBundlePath: isCore
? `${regularBundlePath}/core/core.entry.js` ? `${regularBundlePath}/core/core.entry.js`
: `${regularBundlePath}/${app.getId()}.bundle.js`, : `${regularBundlePath}/${app.getId()}.bundle.js`,

View file

@ -72,43 +72,57 @@ export function createBundlesRoute({
} }
return [ return [
buildRouteForBundles( buildRouteForBundles({
`${basePublicPath}/bundles/kbn-ui-shared-deps/`, publicPath: `${basePublicPath}/bundles/kbn-ui-shared-deps/`,
'/bundles/kbn-ui-shared-deps/', routePath: '/bundles/kbn-ui-shared-deps/',
UiSharedDeps.distDir, bundlesPath: UiSharedDeps.distDir,
fileHashCache fileHashCache,
), replacePublicPath: false,
}),
...npUiPluginPublicDirs.map(({ id, path }) => ...npUiPluginPublicDirs.map(({ id, path }) =>
buildRouteForBundles( buildRouteForBundles({
`${basePublicPath}/bundles/plugin/${id}/`, publicPath: `${basePublicPath}/bundles/plugin/${id}/`,
`/bundles/plugin/${id}/`, routePath: `/bundles/plugin/${id}/`,
path, bundlesPath: path,
fileHashCache fileHashCache,
) replacePublicPath: false,
})
), ),
buildRouteForBundles( buildRouteForBundles({
`${basePublicPath}/bundles/core/`, publicPath: `${basePublicPath}/bundles/core/`,
`/bundles/core/`, routePath: `/bundles/core/`,
fromRoot(join('src', 'core', 'target', 'public')), bundlesPath: fromRoot(join('src', 'core', 'target', 'public')),
fileHashCache fileHashCache,
), replacePublicPath: false,
buildRouteForBundles( }),
`${basePublicPath}/bundles/`, buildRouteForBundles({
'/bundles/', publicPath: `${basePublicPath}/bundles/`,
regularBundlesPath, routePath: '/bundles/',
fileHashCache bundlesPath: regularBundlesPath,
), fileHashCache,
buildRouteForBundles( }),
`${basePublicPath}/built_assets/dlls/`, buildRouteForBundles({
'/built_assets/dlls/', publicPath: `${basePublicPath}/built_assets/dlls/`,
dllBundlesPath, routePath: '/built_assets/dlls/',
fileHashCache bundlesPath: dllBundlesPath,
), fileHashCache,
buildRouteForBundles(`${basePublicPath}/`, '/built_assets/css/', builtCssPath, fileHashCache), }),
buildRouteForBundles({
publicPath: `${basePublicPath}/`,
routePath: '/built_assets/css/',
bundlesPath: builtCssPath,
fileHashCache,
}),
]; ];
} }
function buildRouteForBundles(publicPath, routePath, bundlesPath, fileHashCache) { function buildRouteForBundles({
publicPath,
routePath,
bundlesPath,
fileHashCache,
replacePublicPath = true,
}) {
return { return {
method: 'GET', method: 'GET',
path: `${routePath}{path*}`, path: `${routePath}{path*}`,
@ -129,6 +143,7 @@ function buildRouteForBundles(publicPath, routePath, bundlesPath, fileHashCache)
bundlesPath, bundlesPath,
fileHashCache, fileHashCache,
publicPath, publicPath,
replacePublicPath,
}); });
}, },
}, },

View file

@ -52,7 +52,7 @@ import { replacePlaceholder } from '../public_path_placeholder';
* @property {LruCache} options.fileHashCache * @property {LruCache} options.fileHashCache
*/ */
export async function createDynamicAssetResponse(options) { export async function createDynamicAssetResponse(options) {
const { request, h, bundlesPath, publicPath, fileHashCache } = options; const { request, h, bundlesPath, publicPath, fileHashCache, replacePublicPath } = options;
let fd; let fd;
try { try {
@ -78,11 +78,14 @@ export async function createDynamicAssetResponse(options) {
}); });
fd = null; // read stream is now responsible for fd fd = null; // read stream is now responsible for fd
const content = replacePublicPath ? replacePlaceholder(read, publicPath) : read;
const etag = replacePublicPath ? `${hash}-${publicPath}` : hash;
return h return h
.response(replacePlaceholder(read, publicPath)) .response(content)
.takeover() .takeover()
.code(200) .code(200)
.etag(`${hash}-${publicPath}`) .etag(etag)
.header('cache-control', 'must-revalidate') .header('cache-control', 'must-revalidate')
.type(request.server.mime.path(path).type); .type(request.server.mime.path(path).type);
} catch (error) { } catch (error) {

View file

@ -53,6 +53,8 @@ module.exports = function(grunt) {
function getKarmaFiles(shardNum) { function getKarmaFiles(shardNum) {
return [ return [
'http://localhost:5610/test_bundle/built_css.css', 'http://localhost:5610/test_bundle/built_css.css',
// Sets global variables normally set by the bootstrap.js script
'http://localhost:5610/test_bundle/karma/globals.js',
...UiSharedDeps.jsDepFilenames.map( ...UiSharedDeps.jsDepFilenames.map(
chunkFilename => `http://localhost:5610/bundles/kbn-ui-shared-deps/${chunkFilename}` chunkFilename => `http://localhost:5610/bundles/kbn-ui-shared-deps/${chunkFilename}`