mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
use cache busting for KP bundles (#64414)
* convert into TS * load plugin scripts in html body * use buildNum as a unique Id for cache busting * add tests for caching * fix tests * remove the last TODO. url should be inlined with assetss server * this logic handled by publicPathMap on the client * cache kbn-shared-deps as well * attempt to fix karma tests * always run file through replace stream * place buildHash at begining of path, include all static files * update bundles_route tests to inject buildNum everywhere * fix karma config to point to right prefix * use isDist naming throughout * explain magic number with variables * restore replacePublicPath option from #64226 * replace one more instance of replacePublicPath * use promisify instead of bluebird + non-null assertions * remove one more magic number Co-authored-by: spalger <spalger@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
5ee6dcd14d
commit
5082ff3252
12 changed files with 195 additions and 61 deletions
|
@ -96,9 +96,12 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
? await uiSettings.get('theme:darkMode')
|
||||
: false;
|
||||
|
||||
const buildHash = server.newPlatform.env.packageInfo.buildNum;
|
||||
const basePath = config.get('server.basePath');
|
||||
const regularBundlePath = `${basePath}/bundles`;
|
||||
const dllBundlePath = `${basePath}/built_assets/dlls`;
|
||||
|
||||
const regularBundlePath = `${basePath}/${buildHash}/bundles`;
|
||||
const dllBundlePath = `${basePath}/${buildHash}/built_assets/dlls`;
|
||||
|
||||
const dllStyleChunks = DllCompiler.getRawDllConfig().chunks.map(
|
||||
chunk => `${dllBundlePath}/vendors${chunk}.style.dll.css`
|
||||
);
|
||||
|
@ -108,15 +111,15 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
|
||||
const styleSheetPaths = [
|
||||
...(isCore ? [] : dllStyleChunks),
|
||||
`${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`,
|
||||
`${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`,
|
||||
...(darkMode
|
||||
? [
|
||||
`${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`,
|
||||
`${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.darkCssDistFilename}`,
|
||||
`${basePath}/node_modules/@kbn/ui-framework/dist/kui_dark.css`,
|
||||
`${regularBundlePath}/dark_theme.style.css`,
|
||||
]
|
||||
: [
|
||||
`${basePath}/bundles/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`,
|
||||
`${regularBundlePath}/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`,
|
||||
`${basePath}/node_modules/@kbn/ui-framework/dist/kui_light.css`,
|
||||
`${regularBundlePath}/light_theme.style.css`,
|
||||
]),
|
||||
|
@ -131,7 +134,7 @@ export function uiRenderMixin(kbnServer, server, config) {
|
|||
)
|
||||
.map(path =>
|
||||
path.localPath.endsWith('.scss')
|
||||
? `${basePath}/built_assets/css/${path.publicPath}`
|
||||
? `${basePath}/${buildHash}/built_assets/css/${path.publicPath}`
|
||||
: `${basePath}/${path.publicPath}`
|
||||
)
|
||||
.reverse(),
|
||||
|
|
|
@ -32,6 +32,7 @@ import { PUBLIC_PATH_PLACEHOLDER } from '../../public_path_placeholder';
|
|||
|
||||
const chance = new Chance();
|
||||
const outputFixture = resolve(__dirname, './fixtures/output');
|
||||
const pluginNoPlaceholderFixture = resolve(__dirname, './fixtures/plugin/no_placeholder');
|
||||
|
||||
const randomWordsCache = new Set();
|
||||
const uniqueRandomWord = () => {
|
||||
|
@ -58,6 +59,9 @@ describe('optimizer/bundle route', () => {
|
|||
dllBundlesPath = outputFixture,
|
||||
basePublicPath = '',
|
||||
builtCssPath = outputFixture,
|
||||
npUiPluginPublicDirs = [],
|
||||
buildHash = '1234',
|
||||
isDist = false,
|
||||
} = options;
|
||||
|
||||
const server = new Hapi.Server();
|
||||
|
@ -69,6 +73,9 @@ describe('optimizer/bundle route', () => {
|
|||
dllBundlesPath,
|
||||
basePublicPath,
|
||||
builtCssPath,
|
||||
npUiPluginPublicDirs,
|
||||
buildHash,
|
||||
isDist,
|
||||
})
|
||||
);
|
||||
|
||||
|
@ -158,7 +165,7 @@ describe('optimizer/bundle route', () => {
|
|||
it('responds with exact file data', async () => {
|
||||
const server = createServer();
|
||||
const response = await server.inject({
|
||||
url: '/bundles/image.png',
|
||||
url: '/1234/bundles/image.png',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(200);
|
||||
|
@ -173,7 +180,7 @@ describe('optimizer/bundle route', () => {
|
|||
it('responds with no content-length and exact file data', async () => {
|
||||
const server = createServer();
|
||||
const response = await server.inject({
|
||||
url: '/bundles/no_placeholder.js',
|
||||
url: '/1234/bundles/no_placeholder.js',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(200);
|
||||
|
@ -187,12 +194,12 @@ describe('optimizer/bundle route', () => {
|
|||
});
|
||||
|
||||
describe('js file with placeholder', () => {
|
||||
it('responds with no content-length and modified file data', async () => {
|
||||
it('responds with no content-length and modifiedfile data ', async () => {
|
||||
const basePublicPath = `/${uniqueRandomWord()}`;
|
||||
const server = createServer({ basePublicPath });
|
||||
|
||||
const response = await server.inject({
|
||||
url: '/bundles/with_placeholder.js',
|
||||
url: '/1234/bundles/with_placeholder.js',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(200);
|
||||
|
@ -204,7 +211,7 @@ describe('optimizer/bundle route', () => {
|
|||
);
|
||||
expect(response.result.indexOf(source)).to.be(-1);
|
||||
expect(response.result).to.be(
|
||||
replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/bundles/`)
|
||||
replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -213,7 +220,7 @@ describe('optimizer/bundle route', () => {
|
|||
it('responds with no content-length and exact file data', async () => {
|
||||
const server = createServer();
|
||||
const response = await server.inject({
|
||||
url: '/bundles/no_placeholder.css',
|
||||
url: '/1234/bundles/no_placeholder.css',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(200);
|
||||
|
@ -231,7 +238,7 @@ describe('optimizer/bundle route', () => {
|
|||
const server = createServer({ basePublicPath });
|
||||
|
||||
const response = await server.inject({
|
||||
url: '/bundles/with_placeholder.css',
|
||||
url: '/1234/bundles/with_placeholder.css',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(200);
|
||||
|
@ -240,7 +247,7 @@ describe('optimizer/bundle route', () => {
|
|||
expect(response.headers).to.have.property('content-type', 'text/css; charset=utf-8');
|
||||
expect(response.result.indexOf(source)).to.be(-1);
|
||||
expect(response.result).to.be(
|
||||
replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/bundles/`)
|
||||
replaceAll(source, PUBLIC_PATH_PLACEHOLDER, `${basePublicPath}/1234/bundles/`)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -250,7 +257,7 @@ describe('optimizer/bundle route', () => {
|
|||
const server = createServer();
|
||||
|
||||
const response = await server.inject({
|
||||
url: '/bundles/../outside_output.js',
|
||||
url: '/1234/bundles/../outside_output.js',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(404);
|
||||
|
@ -267,7 +274,7 @@ describe('optimizer/bundle route', () => {
|
|||
const server = createServer();
|
||||
|
||||
const response = await server.inject({
|
||||
url: '/bundles/non_existent.js',
|
||||
url: '/1234/bundles/non_existent.js',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(404);
|
||||
|
@ -286,7 +293,7 @@ describe('optimizer/bundle route', () => {
|
|||
});
|
||||
|
||||
const response = await server.inject({
|
||||
url: '/bundles/with_placeholder.js',
|
||||
url: '/1234/bundles/with_placeholder.js',
|
||||
});
|
||||
|
||||
expect(response.statusCode).to.be(404);
|
||||
|
@ -306,7 +313,7 @@ describe('optimizer/bundle route', () => {
|
|||
|
||||
sinon.assert.notCalled(createHash);
|
||||
const resp1 = await server.inject({
|
||||
url: '/bundles/no_placeholder.js',
|
||||
url: '/1234/bundles/no_placeholder.js',
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(createHash);
|
||||
|
@ -314,23 +321,23 @@ describe('optimizer/bundle route', () => {
|
|||
expect(resp1.statusCode).to.be(200);
|
||||
|
||||
const resp2 = await server.inject({
|
||||
url: '/bundles/no_placeholder.js',
|
||||
url: '/1234/bundles/no_placeholder.js',
|
||||
});
|
||||
|
||||
sinon.assert.notCalled(createHash);
|
||||
expect(resp2.statusCode).to.be(200);
|
||||
});
|
||||
|
||||
it('is unique per basePublicPath although content is the same', async () => {
|
||||
it('is unique per basePublicPath although content is the same (by default)', async () => {
|
||||
const basePublicPath1 = `/${uniqueRandomWord()}`;
|
||||
const basePublicPath2 = `/${uniqueRandomWord()}`;
|
||||
|
||||
const [resp1, resp2] = await Promise.all([
|
||||
createServer({ basePublicPath: basePublicPath1 }).inject({
|
||||
url: '/bundles/no_placeholder.js',
|
||||
url: '/1234/bundles/no_placeholder.js',
|
||||
}),
|
||||
createServer({ basePublicPath: basePublicPath2 }).inject({
|
||||
url: '/bundles/no_placeholder.js',
|
||||
url: '/1234/bundles/no_placeholder.js',
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -349,13 +356,13 @@ describe('optimizer/bundle route', () => {
|
|||
it('responds with 304 when etag and last modified are sent back', async () => {
|
||||
const server = createServer();
|
||||
const resp = await server.inject({
|
||||
url: '/bundles/with_placeholder.js',
|
||||
url: '/1234/bundles/with_placeholder.js',
|
||||
});
|
||||
|
||||
expect(resp.statusCode).to.be(200);
|
||||
|
||||
const resp2 = await server.inject({
|
||||
url: '/bundles/with_placeholder.js',
|
||||
url: '/1234/bundles/with_placeholder.js',
|
||||
headers: {
|
||||
'if-modified-since': resp.headers['last-modified'],
|
||||
'if-none-match': resp.headers.etag,
|
||||
|
@ -366,4 +373,80 @@ describe('optimizer/bundle route', () => {
|
|||
expect(resp2.result).to.have.length(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('kibana platform assets', () => {
|
||||
describe('caching', () => {
|
||||
describe('for non-distributable mode', () => {
|
||||
it('uses "etag" header to invalidate cache', async () => {
|
||||
const basePublicPath = `/${uniqueRandomWord()}`;
|
||||
|
||||
const npUiPluginPublicDirs = [
|
||||
{
|
||||
id: 'no_placeholder',
|
||||
path: pluginNoPlaceholderFixture,
|
||||
},
|
||||
];
|
||||
const responce = await createServer({ basePublicPath, npUiPluginPublicDirs }).inject({
|
||||
url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
|
||||
});
|
||||
|
||||
expect(responce.statusCode).to.be(200);
|
||||
|
||||
expect(responce.headers.etag).to.be.a('string');
|
||||
expect(responce.headers['cache-control']).to.be('must-revalidate');
|
||||
});
|
||||
|
||||
it('creates the same "etag" header for the same content with the same basePath', async () => {
|
||||
const npUiPluginPublicDirs = [
|
||||
{
|
||||
id: 'no_placeholder',
|
||||
path: pluginNoPlaceholderFixture,
|
||||
},
|
||||
];
|
||||
const [resp1, resp2] = await Promise.all([
|
||||
createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({
|
||||
url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
|
||||
}),
|
||||
createServer({ basePublicPath: '', npUiPluginPublicDirs }).inject({
|
||||
url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
|
||||
}),
|
||||
]);
|
||||
|
||||
expect(resp1.statusCode).to.be(200);
|
||||
expect(resp2.statusCode).to.be(200);
|
||||
|
||||
expect(resp1.rawPayload).to.eql(resp2.rawPayload);
|
||||
|
||||
expect(resp1.headers.etag).to.be.a('string');
|
||||
expect(resp2.headers.etag).to.be.a('string');
|
||||
expect(resp1.headers.etag).to.eql(resp2.headers.etag);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for distributable mode', () => {
|
||||
it('commands to cache assets for each release for a year', async () => {
|
||||
const basePublicPath = `/${uniqueRandomWord()}`;
|
||||
|
||||
const npUiPluginPublicDirs = [
|
||||
{
|
||||
id: 'no_placeholder',
|
||||
path: pluginNoPlaceholderFixture,
|
||||
},
|
||||
];
|
||||
const responce = await createServer({
|
||||
basePublicPath,
|
||||
npUiPluginPublicDirs,
|
||||
isDist: true,
|
||||
}).inject({
|
||||
url: '/1234/bundles/plugin/no_placeholder/no_placeholder.plugin.js',
|
||||
});
|
||||
|
||||
expect(responce.statusCode).to.be(200);
|
||||
|
||||
expect(responce.headers.etag).to.be(undefined);
|
||||
expect(responce.headers['cache-control']).to.be('max-age=31536000');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -47,12 +47,16 @@ export function createBundlesRoute({
|
|||
basePublicPath,
|
||||
builtCssPath,
|
||||
npUiPluginPublicDirs = [],
|
||||
buildHash,
|
||||
isDist = false,
|
||||
}: {
|
||||
regularBundlesPath: string;
|
||||
dllBundlesPath: string;
|
||||
basePublicPath: string;
|
||||
builtCssPath: string;
|
||||
npUiPluginPublicDirs?: NpUiPluginPublicDirs;
|
||||
buildHash: string;
|
||||
isDist?: boolean;
|
||||
}) {
|
||||
// rather than calculate the fileHash on every request, we
|
||||
// provide a cache object to `resolveDynamicAssetResponse()` that
|
||||
|
@ -82,45 +86,51 @@ export function createBundlesRoute({
|
|||
|
||||
return [
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/bundles/kbn-ui-shared-deps/`,
|
||||
routePath: '/bundles/kbn-ui-shared-deps/',
|
||||
publicPath: `${basePublicPath}/${buildHash}/bundles/kbn-ui-shared-deps/`,
|
||||
routePath: `/${buildHash}/bundles/kbn-ui-shared-deps/`,
|
||||
bundlesPath: UiSharedDeps.distDir,
|
||||
fileHashCache,
|
||||
replacePublicPath: false,
|
||||
isDist,
|
||||
}),
|
||||
...npUiPluginPublicDirs.map(({ id, path }) =>
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/bundles/plugin/${id}/`,
|
||||
routePath: `/bundles/plugin/${id}/`,
|
||||
publicPath: `${basePublicPath}/${buildHash}/bundles/plugin/${id}/`,
|
||||
routePath: `/${buildHash}/bundles/plugin/${id}/`,
|
||||
bundlesPath: path,
|
||||
fileHashCache,
|
||||
replacePublicPath: false,
|
||||
isDist,
|
||||
})
|
||||
),
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/bundles/core/`,
|
||||
routePath: `/bundles/core/`,
|
||||
publicPath: `${basePublicPath}/${buildHash}/bundles/core/`,
|
||||
routePath: `/${buildHash}/bundles/core/`,
|
||||
bundlesPath: fromRoot(join('src', 'core', 'target', 'public')),
|
||||
fileHashCache,
|
||||
replacePublicPath: false,
|
||||
isDist,
|
||||
}),
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/bundles/`,
|
||||
routePath: '/bundles/',
|
||||
publicPath: `${basePublicPath}/${buildHash}/bundles/`,
|
||||
routePath: `/${buildHash}/bundles/`,
|
||||
bundlesPath: regularBundlesPath,
|
||||
fileHashCache,
|
||||
isDist,
|
||||
}),
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/built_assets/dlls/`,
|
||||
routePath: '/built_assets/dlls/',
|
||||
publicPath: `${basePublicPath}/${buildHash}/built_assets/dlls/`,
|
||||
routePath: `/${buildHash}/built_assets/dlls/`,
|
||||
bundlesPath: dllBundlesPath,
|
||||
fileHashCache,
|
||||
isDist,
|
||||
}),
|
||||
buildRouteForBundles({
|
||||
publicPath: `${basePublicPath}/`,
|
||||
routePath: '/built_assets/css/',
|
||||
routePath: `/${buildHash}/built_assets/css/`,
|
||||
bundlesPath: builtCssPath,
|
||||
fileHashCache,
|
||||
isDist,
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
@ -131,12 +141,14 @@ function buildRouteForBundles({
|
|||
bundlesPath,
|
||||
fileHashCache,
|
||||
replacePublicPath = true,
|
||||
isDist,
|
||||
}: {
|
||||
publicPath: string;
|
||||
routePath: string;
|
||||
bundlesPath: string;
|
||||
fileHashCache: FileHashCache;
|
||||
replacePublicPath?: boolean;
|
||||
isDist: boolean;
|
||||
}) {
|
||||
return {
|
||||
method: 'GET',
|
||||
|
@ -159,6 +171,7 @@ function buildRouteForBundles({
|
|||
fileHashCache,
|
||||
publicPath,
|
||||
replacePublicPath,
|
||||
isDist,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { resolve } from 'path';
|
||||
import Fs from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { promisify } from 'util';
|
||||
|
||||
import Boom from 'boom';
|
||||
|
@ -26,8 +26,13 @@ import Hapi from 'hapi';
|
|||
|
||||
import { FileHashCache } from './file_hash_cache';
|
||||
import { getFileHash } from './file_hash';
|
||||
// @ts-ignore
|
||||
import { replacePlaceholder } from '../public_path_placeholder';
|
||||
|
||||
const MINUTE = 60;
|
||||
const HOUR = 60 * MINUTE;
|
||||
const DAY = 24 * HOUR;
|
||||
|
||||
const asyncOpen = promisify(Fs.open);
|
||||
const asyncClose = promisify(Fs.close);
|
||||
const asyncFstat = promisify(Fs.fstat);
|
||||
|
@ -58,6 +63,7 @@ export async function createDynamicAssetResponse({
|
|||
publicPath,
|
||||
fileHashCache,
|
||||
replacePublicPath,
|
||||
isDist,
|
||||
}: {
|
||||
request: Hapi.Request;
|
||||
h: Hapi.ResponseToolkit;
|
||||
|
@ -65,6 +71,7 @@ export async function createDynamicAssetResponse({
|
|||
publicPath: string;
|
||||
fileHashCache: FileHashCache;
|
||||
replacePublicPath: boolean;
|
||||
isDist: boolean;
|
||||
}) {
|
||||
let fd: number | undefined;
|
||||
|
||||
|
@ -82,7 +89,7 @@ export async function createDynamicAssetResponse({
|
|||
fd = await asyncOpen(path, 'r');
|
||||
|
||||
const stat = await asyncFstat(fd);
|
||||
const hash = await getFileHash(fileHashCache, path, stat, fd);
|
||||
const hash = isDist ? undefined : await getFileHash(fileHashCache, path, stat, fd);
|
||||
|
||||
const read = Fs.createReadStream(null as any, {
|
||||
fd,
|
||||
|
@ -92,15 +99,21 @@ export async function createDynamicAssetResponse({
|
|||
fd = undefined; // read stream is now responsible for fd
|
||||
|
||||
const content = replacePublicPath ? replacePlaceholder(read, publicPath) : read;
|
||||
const etag = replacePublicPath ? `${hash}-${publicPath}` : hash;
|
||||
|
||||
return h
|
||||
const response = h
|
||||
.response(content)
|
||||
.takeover()
|
||||
.code(200)
|
||||
.etag(etag)
|
||||
.header('cache-control', 'must-revalidate')
|
||||
.type(request.server.mime.path(path).type);
|
||||
|
||||
if (isDist) {
|
||||
response.header('cache-control', `max-age=${365 * DAY}`);
|
||||
} else {
|
||||
response.etag(`${hash}-${publicPath}`);
|
||||
response.header('cache-control', 'must-revalidate');
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (fd) {
|
||||
try {
|
||||
|
|
|
@ -17,11 +17,19 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export function createProxyBundlesRoute({ host, port }: { host: string; port: number }) {
|
||||
export function createProxyBundlesRoute({
|
||||
host,
|
||||
port,
|
||||
buildHash,
|
||||
}: {
|
||||
host: string;
|
||||
port: number;
|
||||
buildHash: string;
|
||||
}) {
|
||||
return [
|
||||
buildProxyRouteForBundles('/bundles/', host, port),
|
||||
buildProxyRouteForBundles('/built_assets/dlls/', host, port),
|
||||
buildProxyRouteForBundles('/built_assets/css/', host, port),
|
||||
buildProxyRouteForBundles(`/${buildHash}/bundles/`, host, port),
|
||||
buildProxyRouteForBundles(`/${buildHash}/built_assets/dlls/`, host, port),
|
||||
buildProxyRouteForBundles(`/${buildHash}/built_assets/css/`, host, port),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import KbnServer from '../legacy/server/kbn_server';
|
||||
|
||||
export type NpUiPluginPublicDirs = Array<{
|
||||
|
|
|
@ -57,6 +57,8 @@ export const optimizeMixin = async (
|
|||
basePublicPath: config.get('server.basePath'),
|
||||
builtCssPath: fromRoot('built_assets/css'),
|
||||
npUiPluginPublicDirs: getNpUiPluginPublicDirs(kbnServer),
|
||||
buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(),
|
||||
isDist: kbnServer.newPlatform.env.packageInfo.dist,
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -49,7 +49,8 @@ export default async (kbnServer, kibanaHapiServer, config) => {
|
|||
config.get('optimize.watchPort'),
|
||||
config.get('server.basePath'),
|
||||
watchOptimizer,
|
||||
getNpUiPluginPublicDirs(kbnServer)
|
||||
getNpUiPluginPublicDirs(kbnServer),
|
||||
kbnServer.newPlatform.env.packageInfo.buildNum.toString()
|
||||
);
|
||||
|
||||
watchOptimizer.status$.subscribe({
|
||||
|
|
|
@ -26,6 +26,7 @@ export default (kbnServer, server, config) => {
|
|||
createProxyBundlesRoute({
|
||||
host: config.get('optimize.watchHost'),
|
||||
port: config.get('optimize.watchPort'),
|
||||
buildHash: kbnServer.newPlatform.env.packageInfo.buildNum.toString(),
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ export default class WatchOptimizer extends BaseOptimizer {
|
|||
});
|
||||
}
|
||||
|
||||
bindToServer(server, basePath, npUiPluginPublicDirs) {
|
||||
bindToServer(server, basePath, npUiPluginPublicDirs, buildHash) {
|
||||
// pause all requests received while the compiler is running
|
||||
// and continue once an outcome is reached (aborting the request
|
||||
// with an error if it was a failure).
|
||||
|
@ -118,6 +118,7 @@ export default class WatchOptimizer extends BaseOptimizer {
|
|||
server.route(
|
||||
createBundlesRoute({
|
||||
npUiPluginPublicDirs: npUiPluginPublicDirs,
|
||||
buildHash,
|
||||
regularBundlesPath: this.compiler.outputPath,
|
||||
dllBundlesPath: DllCompiler.getRawDllConfig().outputPath,
|
||||
basePublicPath: basePath,
|
||||
|
|
|
@ -21,10 +21,11 @@ import { Server } from 'hapi';
|
|||
import { registerHapiPlugins } from '../../legacy/server/http/register_hapi_plugins';
|
||||
|
||||
export default class WatchServer {
|
||||
constructor(host, port, basePath, optimizer, npUiPluginPublicDirs) {
|
||||
constructor(host, port, basePath, optimizer, npUiPluginPublicDirs, buildHash) {
|
||||
this.basePath = basePath;
|
||||
this.optimizer = optimizer;
|
||||
this.npUiPluginPublicDirs = npUiPluginPublicDirs;
|
||||
this.buildHash = buildHash;
|
||||
this.server = new Server({
|
||||
host: host,
|
||||
port: port,
|
||||
|
@ -35,7 +36,12 @@ export default class WatchServer {
|
|||
|
||||
async init() {
|
||||
await this.optimizer.init();
|
||||
this.optimizer.bindToServer(this.server, this.basePath, this.npUiPluginPublicDirs);
|
||||
this.optimizer.bindToServer(
|
||||
this.server,
|
||||
this.basePath,
|
||||
this.npUiPluginPublicDirs,
|
||||
this.buildHash
|
||||
);
|
||||
await this.server.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import { DllCompiler } from '../../src/optimize/dynamic_dll_plugin';
|
|||
|
||||
const TOTAL_CI_SHARDS = 4;
|
||||
const ROOT = dirname(require.resolve('../../package.json'));
|
||||
const buildHash = String(Number.MAX_SAFE_INTEGER);
|
||||
|
||||
module.exports = function(grunt) {
|
||||
function pickBrowser() {
|
||||
|
@ -57,27 +58,30 @@ module.exports = function(grunt) {
|
|||
'http://localhost:5610/test_bundle/karma/globals.js',
|
||||
|
||||
...UiSharedDeps.jsDepFilenames.map(
|
||||
chunkFilename => `http://localhost:5610/bundles/kbn-ui-shared-deps/${chunkFilename}`
|
||||
chunkFilename =>
|
||||
`http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${chunkFilename}`
|
||||
),
|
||||
`http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.jsFilename}`,
|
||||
`http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${UiSharedDeps.jsFilename}`,
|
||||
|
||||
'http://localhost:5610/built_assets/dlls/vendors_runtime.bundle.dll.js',
|
||||
`http://localhost:5610/${buildHash}/built_assets/dlls/vendors_runtime.bundle.dll.js`,
|
||||
...DllCompiler.getRawDllConfig().chunks.map(
|
||||
chunk => `http://localhost:5610/built_assets/dlls/vendors${chunk}.bundle.dll.js`
|
||||
chunk =>
|
||||
`http://localhost:5610/${buildHash}/built_assets/dlls/vendors${chunk}.bundle.dll.js`
|
||||
),
|
||||
|
||||
shardNum === undefined
|
||||
? `http://localhost:5610/bundles/tests.bundle.js`
|
||||
: `http://localhost:5610/bundles/tests.bundle.js?shards=${TOTAL_CI_SHARDS}&shard_num=${shardNum}`,
|
||||
? `http://localhost:5610/${buildHash}/bundles/tests.bundle.js`
|
||||
: `http://localhost:5610/${buildHash}/bundles/tests.bundle.js?shards=${TOTAL_CI_SHARDS}&shard_num=${shardNum}`,
|
||||
|
||||
`http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`,
|
||||
`http://localhost:5610/${buildHash}/bundles/kbn-ui-shared-deps/${UiSharedDeps.baseCssDistFilename}`,
|
||||
// this causes tilemap tests to fail, probably because the eui styles haven't been
|
||||
// included in the karma harness a long some time, if ever
|
||||
// `http://localhost:5610/bundles/kbn-ui-shared-deps/${UiSharedDeps.lightCssDistFilename}`,
|
||||
...DllCompiler.getRawDllConfig().chunks.map(
|
||||
chunk => `http://localhost:5610/built_assets/dlls/vendors${chunk}.style.dll.css`
|
||||
chunk =>
|
||||
`http://localhost:5610/${buildHash}/built_assets/dlls/vendors${chunk}.style.dll.css`
|
||||
),
|
||||
'http://localhost:5610/bundles/tests.style.css',
|
||||
`http://localhost:5610/${buildHash}/bundles/tests.style.css`,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -127,9 +131,9 @@ module.exports = function(grunt) {
|
|||
|
||||
proxies: {
|
||||
'/tests/': 'http://localhost:5610/tests/',
|
||||
'/bundles/': 'http://localhost:5610/bundles/',
|
||||
'/built_assets/dlls/': 'http://localhost:5610/built_assets/dlls/',
|
||||
'/test_bundle/': 'http://localhost:5610/test_bundle/',
|
||||
[`/${buildHash}/bundles/`]: `http://localhost:5610/${buildHash}/bundles/`,
|
||||
[`/${buildHash}/built_assets/dlls/`]: `http://localhost:5610/${buildHash}/built_assets/dlls/`,
|
||||
},
|
||||
|
||||
client: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue