mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-29 08:57:03 +02:00
feat(v2): webpack multicompile client & server (#1363)
* feat(v2): multi-compile server & client * simplify stuff * dep * fix sitemap callback deprecation warning
This commit is contained in:
parent
ecb4f91669
commit
f37300a69b
7 changed files with 64 additions and 19 deletions
|
@ -55,7 +55,11 @@ class DocusaurusPluginSitemap {
|
|||
|
||||
// Write sitemap file
|
||||
const sitemapPath = path.join(outDir, 'sitemap.xml');
|
||||
return fs.writeFile(sitemapPath, generatedSitemap);
|
||||
fs.writeFile(sitemapPath, generatedSitemap, err => {
|
||||
if (err) {
|
||||
throw new Error(`Sitemap error: ${err}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ import {Helmet} from 'react-helmet';
|
|||
import {getBundles} from 'react-loadable-ssr-addon';
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import manifest from '@generated/assets-manifest.json'; //eslint-disable-line
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import routes from '@generated/routes'; // eslint-disable-line
|
||||
import preload from './preload';
|
||||
import App from './App';
|
||||
|
@ -42,6 +43,10 @@ export default function render(locals) {
|
|||
];
|
||||
const metaAttributes = metaStrings.filter(Boolean);
|
||||
|
||||
const {outDir} = locals;
|
||||
const manifestPath = path.join(outDir, 'client-manifest.json');
|
||||
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
||||
|
||||
// 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);
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const MemoryFS = require('memory-fs');
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
|
||||
const path = require('path');
|
||||
|
@ -19,13 +18,9 @@ const createServerConfig = require('../webpack/server');
|
|||
const createClientConfig = require('../webpack/client');
|
||||
const {applyConfigureWebpack} = require('../webpack/utils');
|
||||
|
||||
function compile(config, isServer) {
|
||||
function compile(config) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const compiler = webpack(config);
|
||||
if (isServer) {
|
||||
// Don't output server bundle to disk. Write files to memory instead
|
||||
compiler.outputFileSystem = new MemoryFS();
|
||||
}
|
||||
compiler.run((err, stats) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
|
@ -84,13 +79,11 @@ module.exports = async function build(siteDir, cliOptions = {}) {
|
|||
);
|
||||
});
|
||||
|
||||
// Build the client bundles first.
|
||||
// We cannot run them in parallel because the server needs to know
|
||||
// the correct client bundle name.
|
||||
await compile(clientConfig);
|
||||
// Run webpack to build js bundle (client) and static html files (server) !!
|
||||
await compile([clientConfig, serverConfig]);
|
||||
|
||||
// Build the server bundles (render the static HTML and pick client bundle),
|
||||
await compile(serverConfig, true);
|
||||
// Remove server.bundle.js because it is useless
|
||||
await fs.unlink(path.join(outDir, serverConfig.output.filename));
|
||||
|
||||
// Copy static files.
|
||||
const staticDir = path.resolve(siteDir, 'static');
|
||||
|
|
|
@ -15,7 +15,6 @@ module.exports = function createClientConfig(props) {
|
|||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const config = createBaseConfig(props);
|
||||
|
||||
const {generatedFilesDir} = props;
|
||||
const clientConfig = merge(config, {
|
||||
entry: {
|
||||
main: path.resolve(__dirname, '../client/clientEntry.js'),
|
||||
|
@ -26,9 +25,9 @@ module.exports = function createClientConfig(props) {
|
|||
runtimeChunk: true,
|
||||
},
|
||||
plugins: [
|
||||
// Generate manifests file
|
||||
// Generate client manifests file
|
||||
new ReactLoadableSSRAddon({
|
||||
filename: path.resolve(generatedFilesDir, 'assets-manifest.json'),
|
||||
filename: 'client-manifest.json',
|
||||
}),
|
||||
// Show compilation progress bar and build time.
|
||||
new WebpackNiceLog({
|
||||
|
|
38
packages/docusaurus/lib/webpack/plugins/WaitPlugin.js
Normal file
38
packages/docusaurus/lib/webpack/plugins/WaitPlugin.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
const fs = require('fs');
|
||||
|
||||
class WaitPlugin {
|
||||
constructor(options) {
|
||||
this.timeout = options.timeout || 60000;
|
||||
this.interval = options.interval || 250;
|
||||
this.filepath = options.filepath;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
// Before finishing the compilation step
|
||||
compiler.hooks.make.tapAsync('WaitPlugin', (compilation, callback) => {
|
||||
const start = Date.now();
|
||||
const {filepath, timeout, interval} = this;
|
||||
|
||||
// Poll until file exist
|
||||
function poll() {
|
||||
if (fs.existsSync(filepath)) {
|
||||
callback();
|
||||
} else if (Date.now() - start > timeout) {
|
||||
throw Error("Maybe it just wasn't meant to be.");
|
||||
} else {
|
||||
setTimeout(poll, interval);
|
||||
}
|
||||
}
|
||||
|
||||
poll();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WaitPlugin;
|
|
@ -11,9 +11,10 @@ const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin'
|
|||
const WebpackNiceLog = require('webpack-nicelog');
|
||||
const merge = require('webpack-merge');
|
||||
const createBaseConfig = require('./base');
|
||||
const WaitPlugin = require('./plugins/WaitPlugin');
|
||||
|
||||
module.exports = function createServerConfig(props) {
|
||||
const {baseUrl, routesPaths} = props;
|
||||
const {baseUrl, routesPaths, outDir} = props;
|
||||
const config = createBaseConfig(props, true);
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
|
@ -31,11 +32,17 @@ module.exports = function createServerConfig(props) {
|
|||
// No need to bundle its node_modules dependencies since we're bundling for static html generation (backend)
|
||||
externals: [nodeExternals()],
|
||||
plugins: [
|
||||
// Wait until client-manifest is generated
|
||||
new WaitPlugin({
|
||||
filepath: path.join(outDir, 'client-manifest.json'),
|
||||
}),
|
||||
|
||||
// Static site generator webpack plugin.
|
||||
new StaticSiteGeneratorPlugin({
|
||||
entry: 'main',
|
||||
locals: {
|
||||
baseUrl,
|
||||
outDir,
|
||||
},
|
||||
paths: routesPaths,
|
||||
}),
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
"html-webpack-plugin": "^3.2.0",
|
||||
"is-wsl": "^1.1.0",
|
||||
"lodash": "^4.17.11",
|
||||
"memory-fs": "^0.4.1",
|
||||
"mini-css-extract-plugin": "^0.4.1",
|
||||
"portfinder": "^1.0.13",
|
||||
"react-dev-utils": "^8.0.0",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue