Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(v2): reduce HTML payload by eliminating chunk-map #2118

Merged
merged 3 commits into from
Dec 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions packages/docusaurus/src/client/docusaurus.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const docusaurus = {
if (!canPrefetch(routePath)) {
return false;
}
// prevent future duplicate prefetch of routePath
fetched[routePath] = true;

// Find all webpack chunk names needed
const matches = matchRoutes(routes, routePath);
Expand All @@ -51,12 +53,14 @@ const docusaurus = {
}, []);

// Prefetch all webpack chunk assets file needed
const chunkAssetsNeeded = chunkNamesNeeded.reduce((arr, chunkName) => {
const chunkAssets = window.__chunkMapping[chunkName] || [];
return arr.concat(chunkAssets);
}, []);
Promise.all(chunkAssetsNeeded.map(prefetchHelper)).then(() => {
fetched[routePath] = true;
chunkNamesNeeded.forEach(chunkName => {
// "__webpack_require__.gca" is a custom function provided by ChunkAssetPlugin
// Pass it the chunkName or chunkId you want to load and it will return the URL for that chunk
// eslint-disable-next-line no-undef
const chunkAsset = __webpack_require__.gca(chunkName);
if (chunkAsset) {
prefetchHelper(chunkAsset);
}
});
return true;
},
Expand Down
13 changes: 0 additions & 13 deletions packages/docusaurus/src/client/serverEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,6 @@ export default async function render(locals) {
const manifestPath = path.join(generatedFilesDir, 'client-manifest.json');
const manifest = JSON.parse(await fs.readFile(manifestPath, 'utf8'));

// chunkName -> chunkAssets mapping.
const chunkManifestPath = path.join(generatedFilesDir, 'chunk-map.json');
const chunkManifest = JSON.parse(
await fs.readFile(chunkManifestPath, 'utf8'),
);
const chunkManifestScript =
`<script type="text/javascript">` +
`/*<![CDATA[*/window.__chunkMapping=${JSON.stringify(
chunkManifest,
)};/*]]>*/` +
`</script>`;

// Get all required assets for this particular page based on client manifest information
const modulesToBeLoaded = [...manifest.entrypoints, ...Array.from(modules)];
const bundles = getBundles(manifest, modulesToBeLoaded);
Expand All @@ -73,7 +61,6 @@ export default async function render(locals) {
{
appHtml,
baseUrl,
chunkManifestScript,
htmlAttributes: htmlAttributes || '',
bodyAttributes: bodyAttributes || '',
headTags,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ module.exports = `
<meta name="viewport" content="width=device-width">
<meta name="generator" content="Docusaurus">
<%- headTags %>
<%- chunkManifestScript %>
<% metaAttributes.forEach((metaAttribute) => { %>
<%- metaAttribute %>
<% }); %>
Expand Down
14 changes: 4 additions & 10 deletions packages/docusaurus/src/commands/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,10 @@ export async function build(
);
});

// Make sure generated client-manifest and chunk-map is cleaned first so we don't reuse the one from prevs build
const chunkManifestPath = path.join(generatedFilesDir, 'chunk-map.json');
await Promise.all(
[clientManifestPath, chunkManifestPath].map(async manifestPath => {
const manifestExist = await fs.pathExists(manifestPath);
if (manifestExist) {
await fs.unlink(manifestPath);
}
}),
);
// Make sure generated client-manifest is cleaned first so we don't reuse the one from prevs build
if (fs.existsSync(clientManifestPath)) {
fs.unlinkSync(clientManifestPath);
}

// Run webpack to build JS bundle (client) and static html files (server).
await compile([clientConfig, serverConfig]);
Expand Down
10 changes: 2 additions & 8 deletions packages/docusaurus/src/webpack/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import merge from 'webpack-merge';

import {Props} from '@docusaurus/types';
import {createBaseConfig} from './base';
import ChunkManifestPlugin from './plugins/ChunkManifestPlugin';
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
import LogPlugin from './plugins/LogPlugin';

export function createClientConfig(props: Props): Configuration {
Expand All @@ -30,13 +30,7 @@ export function createClientConfig(props: Props): Configuration {
runtimeChunk: true,
},
plugins: [
// Generate chunk-map.json (mapping of chunk names to their corresponding chunk assets)
new ChunkManifestPlugin({
filename: 'chunk-map.json',
outputPath: props.generatedFilesDir,
manifestVariable: '__chunkMapping',
inlineManifest: !isProd,
}),
new ChunkAssetPlugin(),
// Show compilation progress bar and build time.
new LogPlugin({
name: 'Client',
Expand Down
44 changes: 44 additions & 0 deletions packages/docusaurus/src/webpack/plugins/ChunkAssetPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import {Template, Compiler} from 'webpack';
endiliey marked this conversation as resolved.
Show resolved Hide resolved

const pluginName = 'chunk-asset-plugin';

class ChunkAssetPlugin {
apply(compiler: Compiler) {
compiler.hooks.thisCompilation.tap(pluginName, ({mainTemplate}) => {
/* We modify webpack runtime to add an extra function called "__webpack_require__.gca"
that will allow us to get the corresponding chunk asset for a webpack chunk.
Pass it the chunkName or chunkId you want to load.
For example: if you have a chunk named "my-chunk-name" that will map to "/0a84b5e7.c8e35c7a.js" as its corresponding output path
__webpack_require__.gca("my-chunk-name") will return "/0a84b5e7.c8e35c7a.js"*/
mainTemplate.hooks.requireExtensions.tap(pluginName, (source, chunk) => {
const chunkIdToName = chunk.getChunkMaps(false).name;
const chunkNameToId = Object.create(null);
for (const chunkId of Object.keys(chunkIdToName)) {
const chunkName = chunkIdToName[chunkId];
chunkNameToId[chunkName] = chunkId;
}
const buf = [source];
buf.push('');
buf.push('// function to get chunk assets');
buf.push(
mainTemplate.requireFn +
// If chunkName is passed, we convert it to chunk id
// Note that jsonpScriptSrc is an internal webpack function
`.gca = function(chunkId) { chunkId = ${JSON.stringify(
chunkNameToId,
)}[chunkId]||chunkId; return jsonpScriptSrc(chunkId); };`,
);
return Template.asString(buf);
});
});
}
}

export default ChunkAssetPlugin;
89 changes: 0 additions & 89 deletions packages/docusaurus/src/webpack/plugins/ChunkManifestPlugin.js

This file was deleted.