mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-29 10:17:55 +02:00
feat(v2): Webpack 5, PostCSS 8 (#4089)
* Initial webpack 5 work * It works on my machine (lol) * Committing a bit more work * It works - sorta * Update packages/docusaurus/package.json * at least fix prettier /shrug * making more progress. build should work now, css stuff is still a bit broken * Terser things Signed-off-by: Reece Dunham <me@rdil.rocks> * Working on things * Vendor webpack * Repair chunks, and tests * Rerun prettier * Re-add client prefetching * Update snapshots * Update snapshots * I hope this works * Remove redundant dev server code * relock * Trying to reduce memory usage and fix things * Dead code elim * Search bar works!!! * Prefetching should work again * lock * ts issue * Repair snapshot * Run prettier * Fix the CI for now * fix lint-prettier * clean-css works, now for the other one * Fix lockfile * Fixes prettier * Other css minification works!!! * Add clean-css options, fix webpack versions Signed-off-by: Reece Dunham <me@rdil.rocks> * Fix tests and several of the webpack loaders Signed-off-by: Reece Dunham <me@rdil.rocks> * Re-add support for simple css minifier * Update other related dependencies * Fix lockfile * Dev server fixups Signed-off-by: Reece Dunham <me@rdil.rocks> * Simplify css things * Update webpack, try with postcss 7 * Other cssnano repairs * fix lockfile * Clean up the babel preset * Fix lockfile * Bump RL SSR version * Fix the build errors * Lockfile fix * It works again * webpack 5 should close compiler after run * add proper webpack5 persistent caching config * upgrade webpack deps again * reduce build perf timeouts to avoid build time regressions * test if incremental build can run on netlify * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * test * test * test * test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * netlify test * fix existsSync() calls * replace @ts-nocheck by a temporary Webpack type * replace @ts-nocheck by a temporary Webpack type * replace @ts-nocheck by a temporary Webpack type * migrate existing stats.warningsFilter to config.ignoreWarnings * remove stats from postBuild lifecycle data doc, as it is likely unused (we'll add it back if someone ask for it) * improve build.ts TS issues + move some sync code to async * cleanup TS of start.ts * fix TS error * fix TS issues * fix TS issues * fix ts error * netlify test * netlify test * netlify test * netlify test * netlify test * script cleanup * script cleanup * re-enable @typescript-eslint/ban-ts-comment * Deprecate getCacheLoader / getBabelLoader but keep retrocompatibility * useless TS * fix and comment gca(chunkName) prefetching function * remove deprecated mainTemplate.requireFn * temporarily use react-loadable-ssr-addon-v5-slorber until PR merged: https://github.com/facebook/docusaurus/pull/4089 * comment unsafeCache option * add explicit and more precise webpack targets * splitChunks, use new type: "css/mini-extract" as it seems recommended for webpack 5 * webpack error handling: - log error.details as documented - keep using react-dev-utils/formatWebpackMessages for now * fix webpack5 warnings for evalSourceMapMiddleware.js * typo * rename webpackHotDevClient * make all modifications of react-dev-utils explicit with a comment * revert LogPlugin adapter * loader-utils update * add useful share cache comment * add useful comments regarding the null-loader used in SSR for css files * upgrade webpack-merge in a retrocompatible way * use MiniCssExtractPlugin.emit false as recommended * use @docusaurus/responsive-loader * revert MiniCssExtractPlugin esModule: false change * add link to PR for custom CleanWebpackPlugin * pwa: add fallback to env variable or webpack 5 fails to build * upgrade to CssMinimizerPlugin 2.0 * only build en locale for windows tests * line breaks between errors * add useful comment * Fix e2e tests with Yarn2 not finding new init template dependencies * fix bad import * disable browserslist target as webpack already tries to use browserlists if a config is found, and it is a problem for existing sites * webpack5 TS fixes * fix getMinimizer order (even if it does not work yet) * update postcss to v8, fix cssnano minimizer errors * add NavbarItem position to types (useful for QuestDB site upgrade to Webpack5) * add webpack cache env variable to reduce risk of webpack 5 adoption Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
27b9f34635
commit
05e7250c08
63 changed files with 1790 additions and 1556 deletions
4
.github/workflows/v2-build-time-perf.yml
vendored
4
.github/workflows/v2-build-time-perf.yml
vendored
|
@ -25,11 +25,11 @@ jobs:
|
|||
# Ensure build with a cold cache does not increase too much
|
||||
- name: Build (cold cache)
|
||||
run: yarn workspace docusaurus-2-website build --locale en
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 8
|
||||
|
||||
# Ensure build with a warm cache does not increase too much
|
||||
- name: Build (warm cache)
|
||||
run: yarn workspace docusaurus-2-website build --locale en
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 2
|
||||
|
||||
# TODO post a Github comment with build with perf warnings?
|
||||
|
|
2
.github/workflows/v2-tests-windows.yml
vendored
2
.github/workflows/v2-tests-windows.yml
vendored
|
@ -27,6 +27,6 @@ jobs:
|
|||
- name: Docusaurus Jest Tests
|
||||
run: yarn test
|
||||
- name: Docusaurus Build
|
||||
run: yarn build:v2
|
||||
run: yarn build:v2 --locale en
|
||||
env:
|
||||
CI: true
|
||||
|
|
|
@ -71,10 +71,11 @@
|
|||
"@formatjs/intl-datetimeformat": "^3.2.12",
|
||||
"@formatjs/intl-numberformat": "^6.2.2",
|
||||
"@formatjs/intl-pluralrules": "^4.0.11",
|
||||
"@types/cssnano": "^4.0.0",
|
||||
"@types/express": "^4.17.2",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/loader-utils": "^1.1.3",
|
||||
"@types/loader-utils": "^2.0.2",
|
||||
"@types/lodash": "^4.14.168",
|
||||
"@types/node": "^14.14.22",
|
||||
"@types/prismjs": "^1.16.2",
|
||||
|
@ -87,9 +88,7 @@
|
|||
"@types/semver": "^7.1.0",
|
||||
"@types/shelljs": "^0.8.6",
|
||||
"@types/wait-on": "^5.2.0",
|
||||
"@types/webpack": "^4.41.0",
|
||||
"@types/webpack-dev-server": "^3.9.0",
|
||||
"@types/webpack-merge": "^4.1.5",
|
||||
"@types/webpack-dev-server": "^3.11.1",
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"concurrently": "^5.3.0",
|
||||
|
|
|
@ -9,14 +9,17 @@ const advancedBasePreset = require('cssnano-preset-advanced');
|
|||
const postCssSortMediaQueries = require('postcss-sort-media-queries');
|
||||
const postCssRemoveOverriddenCustomProperties = require('./src/remove-overridden-custom-properties');
|
||||
|
||||
const preset = advancedBasePreset({
|
||||
autoprefixer: {add: false},
|
||||
discardComments: {removeAll: true},
|
||||
});
|
||||
module.exports = function docusaurusCssnanoPreset(opts) {
|
||||
const advancedPreset = advancedBasePreset({
|
||||
autoprefixer: {add: false},
|
||||
discardComments: {removeAll: true},
|
||||
...opts,
|
||||
});
|
||||
|
||||
preset.plugins.unshift(
|
||||
[postCssSortMediaQueries],
|
||||
[postCssRemoveOverriddenCustomProperties],
|
||||
);
|
||||
advancedPreset.plugins.unshift(
|
||||
[postCssSortMediaQueries],
|
||||
[postCssRemoveOverriddenCustomProperties],
|
||||
);
|
||||
|
||||
module.exports = preset;
|
||||
return advancedPreset;
|
||||
};
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
"directory": "packages/docusaurus-cssnano-preset"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssnano-preset-advanced": "^4.0.7",
|
||||
"postcss": "^7.0.2",
|
||||
"postcss-sort-media-queries": "^1.7.26"
|
||||
"cssnano-preset-advanced": "^5.0.0",
|
||||
"postcss": "^8.2.10",
|
||||
"postcss-sort-media-queries": "^3.8.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"to-vfile": "^6.0.0"
|
||||
|
|
|
@ -5,40 +5,38 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const postcss = require('postcss');
|
||||
/**
|
||||
* This PostCSS plugin will remove duplicate/same custom properties (which are actually overridden ones) **only** from `:root` selector.
|
||||
*
|
||||
* Depending on the presence of an `!important` rule in value of custom property, the following actions will happens:
|
||||
*
|
||||
* - If the same custom properties do **not** have an `!important` rule, then all of them will be removed except for the last one (which will actually be applied).
|
||||
* - If the same custom properties have at least one `!important` rule, then only those properties that do not have this rule will be removed.
|
||||
* @returns {import('postcss').Plugin}
|
||||
*/
|
||||
module.exports = function creator() {
|
||||
return {
|
||||
postcssPlugin: 'postcss-remove-overridden-custom-properties',
|
||||
Declaration(decl) {
|
||||
if (decl.parent.selector !== ':root') {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
This PostCSS plugin will remove duplicate/same custom properties (which are actually overridden ones) **only** from `:root` selector.
|
||||
const sameProperties =
|
||||
decl.parent.nodes.filter((n) => n.prop === decl.prop) || [];
|
||||
const hasImportantProperties = sameProperties.some((p) =>
|
||||
Object.prototype.hasOwnProperty.call(p, 'important'),
|
||||
);
|
||||
|
||||
Depending on the presence of an `!important` rule in value of custom property, the following actions will happens:
|
||||
const overriddenProperties = hasImportantProperties
|
||||
? sameProperties.filter(
|
||||
(p) => !Object.prototype.hasOwnProperty.call(p, 'important'),
|
||||
)
|
||||
: sameProperties.slice(0, -1);
|
||||
|
||||
- If the same custom properties do **not** have an `!important` rule, then all of them will be removed except for the last one (which will actually be applied).
|
||||
- If the same custom properties have at least one `!important` rule, then only those properties that do not have this rule will be removed.
|
||||
*/
|
||||
overriddenProperties.map((p) => p.remove());
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = postcss.plugin(
|
||||
'postcss-remove-overridden-custom-properties',
|
||||
() => {
|
||||
return (root) => {
|
||||
root.walkDecls((decl) => {
|
||||
if (decl.parent.selector !== ':root') {
|
||||
return;
|
||||
}
|
||||
|
||||
const sameProperties =
|
||||
decl.parent.nodes.filter((n) => n.prop === decl.prop) || [];
|
||||
const hasImportantProperties = sameProperties.some((p) =>
|
||||
Object.prototype.hasOwnProperty.call(p, 'important'),
|
||||
);
|
||||
|
||||
const overriddenProperties = hasImportantProperties
|
||||
? sameProperties.filter(
|
||||
(p) => !Object.prototype.hasOwnProperty.call(p, 'important'),
|
||||
)
|
||||
: sameProperties.slice(0, -1);
|
||||
|
||||
overriddenProperties.map((p) => p.remove());
|
||||
});
|
||||
};
|
||||
},
|
||||
);
|
||||
module.exports.postcss = true;
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
"dependencies": {
|
||||
"@docusaurus/core": "2.0.0-alpha.74",
|
||||
"@docusaurus/preset-bootstrap": "2.0.0-alpha.74",
|
||||
"@mdx-js/react": "^1.5.8",
|
||||
"classnames": "^2.2.6",
|
||||
"@mdx-js/react": "^1.6.21",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"clsx": "^1.1.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"react-dom": "^17.0.1",
|
||||
"url-loader": "^4.1.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import clsx from 'clsx';
|
||||
import Layout from '@theme/Layout';
|
||||
import Link from '@docusaurus/Link';
|
||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
const features = [
|
||||
|
@ -43,7 +42,7 @@ const features = [
|
|||
function Feature({imageUrl, title, description}) {
|
||||
const imgUrl = useBaseUrl(imageUrl);
|
||||
return (
|
||||
<div className={classnames('col col--4', styles.feature)}>
|
||||
<div className={clsx('col col--4', styles.feature)}>
|
||||
{imgUrl && (
|
||||
<div className="text--center">
|
||||
<img className={styles.featureImage} src={imgUrl} alt={title} />
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
"@docusaurus/core": "2.0.0-alpha.74",
|
||||
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
||||
"@mdx-js/react": "^1.6.21",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"clsx": "^1.1.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"react-dom": "^17.0.1",
|
||||
"url-loader": "^4.1.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
|
|
@ -21,9 +21,12 @@
|
|||
"@docusaurus/core": "2.0.0-alpha.74",
|
||||
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
||||
"@mdx-js/react": "^1.6.21",
|
||||
"@svgr/webpack": "^5.5.0",
|
||||
"clsx": "^1.1.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1"
|
||||
"react-dom": "^17.0.1",
|
||||
"url-loader": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.13.10",
|
||||
|
|
|
@ -28,13 +28,13 @@
|
|||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^9.1.0",
|
||||
"github-slugger": "^1.3.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"gray-matter": "^4.0.2",
|
||||
"mdast-util-to-string": "^2.0.0",
|
||||
"remark-emoji": "^2.1.0",
|
||||
"stringify-object": "^3.3.0",
|
||||
"unist-util-visit": "^2.0.2",
|
||||
"url-loader": "^4.1.1",
|
||||
"webpack": "^4.44.1"
|
||||
"webpack": "^5.28.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/types": "2.0.0-alpha.74",
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const {getOptions} = require('loader-utils');
|
||||
const {readFile} = require('fs-extra');
|
||||
const mdx = require('@mdx-js/mdx');
|
||||
const emoji = require('remark-emoji');
|
||||
|
@ -27,7 +26,8 @@ const DEFAULT_OPTIONS = {
|
|||
|
||||
module.exports = async function docusaurusMdxLoader(fileString) {
|
||||
const callback = this.async();
|
||||
const reqOptions = getOptions(this) || {};
|
||||
|
||||
const reqOptions = this.getOptions() || {};
|
||||
|
||||
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ const createJSX = (node, pathUrl) => {
|
|||
};
|
||||
|
||||
async function ensureImageFileExist(imagePath, sourceFilePath) {
|
||||
const imageExists = await fs.exists(imagePath);
|
||||
const imageExists = await fs.pathExists(imagePath);
|
||||
if (!imageExists) {
|
||||
throw new Error(
|
||||
`Image ${toMessageRelativeFilePath(
|
||||
|
|
|
@ -20,7 +20,7 @@ const {
|
|||
} = getFileLoaderUtils();
|
||||
|
||||
async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
|
||||
const assetExists = await fs.exists(fileSystemAssetPath);
|
||||
const assetExists = await fs.pathExists(fileSystemAssetPath);
|
||||
if (!assetExists) {
|
||||
throw new Error(
|
||||
`Asset ${toMessageRelativeFilePath(
|
||||
|
@ -85,12 +85,12 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
|||
toAssetLinkNode(fileSystemAssetPath);
|
||||
} else if (path.isAbsolute(assetPath)) {
|
||||
const fileSystemAssetPath = path.join(staticDir, assetPath);
|
||||
if (await fs.exists(fileSystemAssetPath)) {
|
||||
if (await fs.pathExists(fileSystemAssetPath)) {
|
||||
toAssetLinkNode(fileSystemAssetPath);
|
||||
}
|
||||
} else {
|
||||
const fileSystemAssetPath = path.join(path.dirname(filePath), assetPath);
|
||||
if (await fs.exists(fileSystemAssetPath)) {
|
||||
if (await fs.pathExists(fileSystemAssetPath)) {
|
||||
toAssetLinkNode(fileSystemAssetPath);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,12 +27,12 @@
|
|||
"feed": "^4.2.2",
|
||||
"fs-extra": "^9.1.0",
|
||||
"globby": "^11.0.2",
|
||||
"loader-utils": "^1.2.3",
|
||||
"loader-utils": "^2.0.0",
|
||||
"lodash": "^4.17.20",
|
||||
"reading-time": "^1.3.0",
|
||||
"remark-admonitions": "^1.2.1",
|
||||
"tslib": "^2.1.0",
|
||||
"webpack": "^4.44.1"
|
||||
"webpack": "^5.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
@ -44,7 +44,7 @@ import {
|
|||
OptionValidationContext,
|
||||
ValidationResult,
|
||||
} from '@docusaurus/types';
|
||||
import {Configuration, Loader} from 'webpack';
|
||||
import {Configuration} from 'webpack';
|
||||
import {
|
||||
generateBlogFeed,
|
||||
generateBlogPosts,
|
||||
|
@ -401,7 +401,7 @@ export default function pluginContentBlog(
|
|||
configureWebpack(
|
||||
_config: Configuration,
|
||||
isServer: boolean,
|
||||
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
|
||||
{getJSLoader}: ConfigureWebpackUtils,
|
||||
) {
|
||||
const {
|
||||
rehypePlugins,
|
||||
|
@ -441,8 +441,7 @@ export default function pluginContentBlog(
|
|||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||
.map(addTrailingPathSeparator),
|
||||
use: [
|
||||
getCacheLoader(isServer),
|
||||
getBabelLoader(isServer),
|
||||
getJSLoader({isServer}),
|
||||
{
|
||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||
options: {
|
||||
|
@ -466,7 +465,7 @@ export default function pluginContentBlog(
|
|||
loader: path.resolve(__dirname, './markdownLoader.js'),
|
||||
options: markdownLoaderOptions,
|
||||
},
|
||||
].filter(Boolean) as Loader[],
|
||||
].filter(Boolean),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -5,16 +5,21 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {loader} from 'webpack';
|
||||
import {truncate, linkify} from './blogUtils';
|
||||
import {parseQuery, getOptions} from 'loader-utils';
|
||||
import {parseQuery} from 'loader-utils';
|
||||
import {BlogMarkdownLoaderOptions} from './types';
|
||||
|
||||
const markdownLoader: loader.Loader = function (source) {
|
||||
// TODO temporary until Webpack5 export this type
|
||||
// see https://github.com/webpack/webpack/issues/11630
|
||||
interface Loader extends Function {
|
||||
(this: any, source: string): string | Buffer | void | undefined;
|
||||
}
|
||||
|
||||
const markdownLoader: Loader = function (source) {
|
||||
const filePath = this.resourcePath;
|
||||
const fileString = source as string;
|
||||
const callback = this.async();
|
||||
const markdownLoaderOptions = getOptions(this) as BlogMarkdownLoaderOptions;
|
||||
const markdownLoaderOptions = this.getOptions() as BlogMarkdownLoaderOptions;
|
||||
|
||||
// Linkify blog posts
|
||||
let finalContent = linkify({
|
||||
|
@ -24,8 +29,8 @@ const markdownLoader: loader.Loader = function (source) {
|
|||
});
|
||||
|
||||
// Truncate content if requested (e.g: file.md?truncated=true).
|
||||
const truncated: string | undefined = this.resourceQuery
|
||||
? parseQuery(this.resourceQuery).truncated
|
||||
const truncated: boolean | undefined = this.resourceQuery
|
||||
? !!parseQuery(this.resourceQuery).truncated
|
||||
: undefined;
|
||||
|
||||
if (truncated) {
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
"shelljs": "^0.8.4",
|
||||
"tslib": "^2.1.0",
|
||||
"utility-types": "^3.10.0",
|
||||
"webpack": "^4.44.1"
|
||||
"webpack": "^5.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
@ -33,7 +33,6 @@ import {
|
|||
} from '../types';
|
||||
import {toSidebarsProp} from '../props';
|
||||
|
||||
// @ts-expect-error: TODO typedefs missing?
|
||||
import {validate} from 'webpack';
|
||||
import {DefaultSidebarItemsGenerator} from '../sidebarItemsGenerator';
|
||||
|
||||
|
@ -253,7 +252,7 @@ describe('simple website', () => {
|
|||
false,
|
||||
);
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
||||
test('content', async () => {
|
||||
|
|
|
@ -331,7 +331,7 @@ export default function pluginContentDocs(
|
|||
},
|
||||
|
||||
configureWebpack(_config, isServer, utils) {
|
||||
const {getBabelLoader, getCacheLoader} = utils;
|
||||
const {getJSLoader} = utils;
|
||||
const {
|
||||
rehypePlugins,
|
||||
remarkPlugins,
|
||||
|
@ -361,8 +361,7 @@ export default function pluginContentDocs(
|
|||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||
.map(addTrailingPathSeparator),
|
||||
use: compact([
|
||||
getCacheLoader(isServer),
|
||||
getBabelLoader(isServer),
|
||||
getJSLoader({isServer}),
|
||||
{
|
||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||
options: {
|
||||
|
@ -387,16 +386,13 @@ export default function pluginContentDocs(
|
|||
};
|
||||
}
|
||||
|
||||
// Suppress warnings about non-existing of versions file.
|
||||
const stats = {
|
||||
warningsFilter: [VERSIONS_JSON_FILE],
|
||||
};
|
||||
|
||||
return {
|
||||
stats,
|
||||
devServer: {
|
||||
stats,
|
||||
},
|
||||
ignoreWarnings: [
|
||||
// Suppress warnings about non-existing of versions file.
|
||||
(e) =>
|
||||
e.message.includes("Can't resolve") &&
|
||||
e.message.includes(VERSIONS_JSON_FILE),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'~docs': pluginDataDirRoot,
|
||||
|
|
|
@ -5,15 +5,19 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {getOptions} from 'loader-utils';
|
||||
import {loader} from 'webpack';
|
||||
import {linkify} from './linkify';
|
||||
import {DocsMarkdownOption} from '../types';
|
||||
|
||||
const markdownLoader: loader.Loader = function (source) {
|
||||
// TODO temporary until Webpack5 export this type
|
||||
// see https://github.com/webpack/webpack/issues/11630
|
||||
interface Loader extends Function {
|
||||
(this: any, source: string): string | Buffer | void | undefined;
|
||||
}
|
||||
|
||||
const markdownLoader: Loader = function (source) {
|
||||
const fileString = source as string;
|
||||
const callback = this.async();
|
||||
const options = getOptions(this) as DocsMarkdownOption;
|
||||
const options = this.getOptions() as DocsMarkdownOption;
|
||||
return (
|
||||
callback && callback(null, linkify(fileString, this.resourcePath, options))
|
||||
);
|
||||
|
|
|
@ -24,13 +24,12 @@
|
|||
"@docusaurus/utils": "2.0.0-alpha.74",
|
||||
"@docusaurus/utils-validation": "2.0.0-alpha.74",
|
||||
"globby": "^11.0.2",
|
||||
"loader-utils": "^1.2.3",
|
||||
"lodash": "^4.17.20",
|
||||
"minimatch": "^3.0.4",
|
||||
"remark-admonitions": "^1.2.1",
|
||||
"slash": "^3.0.0",
|
||||
"tslib": "^2.1.0",
|
||||
"webpack": "^4.44.1"
|
||||
"webpack": "^5.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
@ -26,7 +26,7 @@ import {
|
|||
ValidationResult,
|
||||
ConfigureWebpackUtils,
|
||||
} from '@docusaurus/types';
|
||||
import {Configuration, Loader} from 'webpack';
|
||||
import {Configuration} from 'webpack';
|
||||
import admonitions from 'remark-admonitions';
|
||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||
import {
|
||||
|
@ -192,7 +192,7 @@ export default function pluginContentPages(
|
|||
configureWebpack(
|
||||
_config: Configuration,
|
||||
isServer: boolean,
|
||||
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
|
||||
{getJSLoader}: ConfigureWebpackUtils,
|
||||
) {
|
||||
const {
|
||||
rehypePlugins,
|
||||
|
@ -214,8 +214,7 @@ export default function pluginContentPages(
|
|||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||
.map(addTrailingPathSeparator),
|
||||
use: [
|
||||
getCacheLoader(isServer),
|
||||
getBabelLoader(isServer),
|
||||
getJSLoader({isServer}),
|
||||
{
|
||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||
options: {
|
||||
|
@ -248,7 +247,7 @@ export default function pluginContentPages(
|
|||
// contentPath,
|
||||
},
|
||||
},
|
||||
].filter(Boolean) as Loader[],
|
||||
].filter(Boolean),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -5,13 +5,16 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {loader} from 'webpack';
|
||||
// import {getOptions} from 'loader-utils';
|
||||
// TODO temporary until Webpack5 export this type
|
||||
// see https://github.com/webpack/webpack/issues/11630
|
||||
interface Loader extends Function {
|
||||
(this: any, source: string): string | Buffer | void | undefined;
|
||||
}
|
||||
|
||||
const markdownLoader: loader.Loader = function (fileString) {
|
||||
const markdownLoader: Loader = function (fileString) {
|
||||
const callback = this.async();
|
||||
|
||||
// const options = getOptions(this);
|
||||
// const options = this.getOptions();
|
||||
|
||||
// TODO provide additinal md processing here? like interlinking pages?
|
||||
// fileString = linkify(fileString)
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
"@docusaurus/lqip-loader": "2.0.0-alpha.74",
|
||||
"@docusaurus/types": "2.0.0-alpha.74",
|
||||
"@endiliey/react-ideal-image": "^0.0.11",
|
||||
"@endiliey/responsive-loader": "^1.3.2",
|
||||
"react-waypoint": "^9.0.2",
|
||||
"@docusaurus/responsive-loader": "1.4.0",
|
||||
"sharp": "^0.27.1",
|
||||
"tslib": "^2.1.0",
|
||||
"webpack": "^4.44.1"
|
||||
"webpack": "^5.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.4 || ^17.0.0",
|
||||
|
|
|
@ -35,12 +35,11 @@ export default function (
|
|||
use: [
|
||||
require.resolve('@docusaurus/lqip-loader'),
|
||||
{
|
||||
loader: require.resolve('@endiliey/responsive-loader'),
|
||||
loader: require.resolve('@docusaurus/responsive-loader'),
|
||||
options: {
|
||||
emitFile: !isServer, // don't emit for server-side rendering
|
||||
disable: !isProd,
|
||||
// eslint-disable-next-line
|
||||
adapter: require('@endiliey/responsive-loader/sharp'),
|
||||
adapter: require('@docusaurus/responsive-loader/sharp'),
|
||||
name: isProd
|
||||
? 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]'
|
||||
: 'assets/ideal-img/[name].[width].[ext]',
|
||||
|
|
|
@ -22,9 +22,9 @@
|
|||
"babel-loader": "^8.2.2",
|
||||
"clsx": "^1.1.1",
|
||||
"core-js": "^2.6.5",
|
||||
"terser-webpack-plugin": "^4.1.0",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack-merge": "^4.2.2",
|
||||
"terser-webpack-plugin": "^5.1.1",
|
||||
"webpack": "^5.28.0",
|
||||
"webpack-merge": "^5.7.3",
|
||||
"workbox-build": "^6.1.1",
|
||||
"workbox-precaching": "^6.1.1",
|
||||
"workbox-window": "^6.1.1"
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const LogPlugin = require('@docusaurus/core/lib/webpack/plugins/LogPlugin');
|
||||
const LogPlugin = require('@docusaurus/core/lib/webpack/plugins/LogPlugin')
|
||||
.default;
|
||||
const {compile} = require('@docusaurus/core/lib/webpack/utils');
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
@ -127,7 +128,7 @@ function plugin(context, options) {
|
|||
},
|
||||
plugins: [
|
||||
new webpack.EnvironmentPlugin({
|
||||
PWA_SW_CUSTOM: swCustom,
|
||||
PWA_SW_CUSTOM: swCustom || '', // fallback value required with Webpack 5
|
||||
}),
|
||||
new LogPlugin({
|
||||
name: 'Service Worker',
|
||||
|
|
|
@ -41,12 +41,12 @@
|
|||
"infima": "0.2.0-alpha.23",
|
||||
"lodash": "^4.17.20",
|
||||
"parse-numeric-range": "^1.2.0",
|
||||
"postcss": "^7.0.2",
|
||||
"postcss": "^8.2.10",
|
||||
"prism-react-renderer": "^1.1.1",
|
||||
"prismjs": "^1.23.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"rtlcss": "^2.6.2"
|
||||
"rtlcss": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "2.0.0-alpha.74"
|
||||
|
|
|
@ -10,7 +10,7 @@ import {ThemeConfig} from '@docusaurus/theme-common';
|
|||
import {getTranslationFiles, translateThemeConfig} from './translations';
|
||||
import path from 'path';
|
||||
import Module from 'module';
|
||||
import postcss, {Root as PostCssRoot} from 'postcss';
|
||||
import type {AcceptedPlugin, Result, Plugin as PostCssPlugin} from 'postcss';
|
||||
import rtlcss from 'rtlcss';
|
||||
import {readDefaultCodeTranslationMessages} from '@docusaurus/utils';
|
||||
|
||||
|
@ -139,14 +139,11 @@ export default function docusaurusThemeClassic(
|
|||
.map((lang) => `prism-${lang}`)
|
||||
.join('|');
|
||||
|
||||
// See https://github.com/facebook/docusaurus/pull/3382
|
||||
const useDocsWarningFilter = (warning: string) =>
|
||||
warning.includes("Can't resolve '@theme-init/hooks/useDocs");
|
||||
|
||||
return {
|
||||
stats: {
|
||||
warningsFilter: useDocsWarningFilter,
|
||||
},
|
||||
ignoreWarnings: [
|
||||
// See https://github.com/facebook/docusaurus/pull/3382
|
||||
(e) => e.message.includes("Can't resolve '@theme-init/hooks/useDocs"),
|
||||
],
|
||||
plugins: [
|
||||
new ContextReplacementPlugin(
|
||||
/prismjs[\\/]components$/,
|
||||
|
@ -156,29 +153,21 @@ export default function docusaurusThemeClassic(
|
|||
};
|
||||
},
|
||||
|
||||
configurePostCss(postCssOptions) {
|
||||
configurePostCss(postCssOptions: {plugins: AcceptedPlugin[]}) {
|
||||
if (direction === 'rtl') {
|
||||
postCssOptions.plugins.push(
|
||||
postcss.plugin('RtlCssPlugin', () => {
|
||||
const resolvedInfimaFile = require.resolve(
|
||||
getInfimaCSSFile(direction),
|
||||
);
|
||||
function isInfimaCSSFile(file?: string) {
|
||||
return file === resolvedInfimaFile;
|
||||
const resolvedInfimaFile = require.resolve(getInfimaCSSFile(direction));
|
||||
const plugin: PostCssPlugin = {
|
||||
postcssPlugin: 'RtlCssPlugin',
|
||||
prepare: (result: Result) => {
|
||||
const file = result.root?.source?.input?.file;
|
||||
// Skip Infima as we are using the its RTL version.
|
||||
if (file === resolvedInfimaFile) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return function (root: PostCssRoot) {
|
||||
const file = root?.source?.input.file;
|
||||
|
||||
// Skip Infima as we are using the its RTL version.
|
||||
if (isInfimaCSSFile(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rtlcss.process(root);
|
||||
};
|
||||
}),
|
||||
);
|
||||
return rtlcss(result.root);
|
||||
},
|
||||
};
|
||||
postCssOptions.plugins.push(plugin);
|
||||
}
|
||||
|
||||
return postCssOptions;
|
||||
|
|
|
@ -15,6 +15,7 @@ export type NavbarItem = {
|
|||
type?: string | undefined;
|
||||
items?: NavbarItem[];
|
||||
label?: string;
|
||||
position?: 'left' | 'right';
|
||||
};
|
||||
|
||||
export type NavbarLogo = {
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/webpack": "^4.41.0",
|
||||
"commander": "^5.1.0",
|
||||
"joi": "^17.4.0",
|
||||
"querystring": "0.2.0",
|
||||
"webpack-merge": "^4.2.2"
|
||||
"webpack": "^5.28.0",
|
||||
"webpack-merge": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
|
34
packages/docusaurus-types/src/index.d.ts
vendored
34
packages/docusaurus-types/src/index.d.ts
vendored
|
@ -7,12 +7,16 @@
|
|||
|
||||
// ESLint doesn't understand types dependencies in d.ts
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import type {Loader, Configuration, Stats} from 'webpack';
|
||||
import type {RuleSetRule, Configuration} from 'webpack';
|
||||
import type {Command} from 'commander';
|
||||
import type {ParsedUrlQueryInput} from 'querystring';
|
||||
import type {MergeStrategy} from 'webpack-merge';
|
||||
import type Joi from 'joi';
|
||||
|
||||
// Convert webpack-merge webpack-merge enum to union type
|
||||
// For type retro-compatible webpack-merge upgrade: we used string literals before)
|
||||
// see https://github.com/survivejs/webpack-merge/issues/179
|
||||
type MergeStrategy = 'match' | 'merge' | 'append' | 'prepend' | 'replace';
|
||||
|
||||
export type ReportingSeverity = 'ignore' | 'log' | 'warn' | 'error' | 'throw';
|
||||
|
||||
export type ThemeConfig = {
|
||||
|
@ -186,18 +190,12 @@ export interface InjectedHtmlTags {
|
|||
export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
|
||||
|
||||
export interface Props extends LoadContext, InjectedHtmlTags {
|
||||
siteMetadata: DocusaurusSiteMetadata;
|
||||
routes: RouteConfig[];
|
||||
routesPaths: string[];
|
||||
plugins: Plugin<unknown>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `Props` but also has webpack stats appended.
|
||||
*/
|
||||
export interface PropsPostBuild extends Props {
|
||||
stats: Stats.ToJsonOutput;
|
||||
}
|
||||
|
||||
export interface PluginContentLoadedActions {
|
||||
addRoute(config: RouteConfig): void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
|
@ -228,7 +226,7 @@ export interface Plugin<Content> {
|
|||
actions: PluginContentLoadedActions;
|
||||
}): void;
|
||||
routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60)
|
||||
postBuild?(props: PropsPostBuild): void;
|
||||
postBuild?(props: Props): void;
|
||||
postStart?(props: Props): void;
|
||||
configureWebpack?(
|
||||
config: Configuration,
|
||||
|
@ -335,15 +333,23 @@ export interface ConfigureWebpackUtils {
|
|||
cssOptions: {
|
||||
[key: string]: unknown;
|
||||
},
|
||||
) => Loader[];
|
||||
) => RuleSetRule[];
|
||||
getJSLoader: (options: {
|
||||
isServer: boolean;
|
||||
babelOptions?: Record<string, unknown>;
|
||||
}) => RuleSetRule;
|
||||
|
||||
// TODO deprecated: remove before end of 2021?
|
||||
getCacheLoader: (
|
||||
isServer: boolean,
|
||||
cacheOptions?: Record<string, unknown>,
|
||||
) => Loader | null;
|
||||
) => RuleSetRule | null;
|
||||
|
||||
// TODO deprecated: remove before end of 2021?
|
||||
getBabelLoader: (
|
||||
isServer: boolean,
|
||||
babelOptions?: Record<string, unknown>,
|
||||
) => Loader;
|
||||
options?: Record<string, unknown>,
|
||||
) => RuleSetRule;
|
||||
}
|
||||
|
||||
interface HtmlTagObject {
|
||||
|
|
|
@ -39,8 +39,6 @@
|
|||
"dependencies": {
|
||||
"@babel/core": "^7.12.16",
|
||||
"@babel/generator": "^7.12.15",
|
||||
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.13",
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.12.16",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||
"@babel/plugin-transform-runtime": "^7.12.15",
|
||||
"@babel/preset-env": "^7.12.16",
|
||||
|
@ -60,14 +58,15 @@
|
|||
"babel-loader": "^8.2.2",
|
||||
"babel-plugin-dynamic-import-node": "2.3.0",
|
||||
"boxen": "^5.0.0",
|
||||
"cache-loader": "^4.1.0",
|
||||
"chalk": "^4.1.0",
|
||||
"chokidar": "^3.5.1",
|
||||
"clean-css": "^5.1.1",
|
||||
"commander": "^5.1.0",
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"copy-webpack-plugin": "^8.1.0",
|
||||
"core-js": "^3.9.1",
|
||||
"css-loader": "^5.1.1",
|
||||
"css-minimizer-webpack-plugin": "^2.0.0",
|
||||
"cssnano": "^5.0.1",
|
||||
"del": "^6.0.0",
|
||||
"detect-port": "^1.3.0",
|
||||
"eta": "^1.12.1",
|
||||
|
@ -78,24 +77,22 @@
|
|||
"globby": "^11.0.2",
|
||||
"html-minifier-terser": "^5.1.1",
|
||||
"html-tags": "^3.1.0",
|
||||
"html-webpack-plugin": "^4.5.0",
|
||||
"html-webpack-plugin": "^5.2.0",
|
||||
"import-fresh": "^3.3.0",
|
||||
"is-root": "^2.1.0",
|
||||
"leven": "^3.1.0",
|
||||
"lodash": "^4.17.20",
|
||||
"mini-css-extract-plugin": "^0.8.0",
|
||||
"mini-css-extract-plugin": "^1.4.0",
|
||||
"module-alias": "^2.2.2",
|
||||
"nprogress": "^0.2.0",
|
||||
"null-loader": "^4.0.0",
|
||||
"optimize-css-assets-webpack-plugin": "^5.0.4",
|
||||
"pnp-webpack-plugin": "^1.6.4",
|
||||
"postcss": "^8.2.7",
|
||||
"postcss-loader": "^4.1.0",
|
||||
"postcss": "^8.2.10",
|
||||
"postcss-loader": "^5.2.0",
|
||||
"prompts": "^2.4.0",
|
||||
"react-dev-utils": "^11.0.1",
|
||||
"react-error-overlay": "^6.0.9",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-loadable": "^5.5.0",
|
||||
"react-loadable-ssr-addon": "^0.3.0",
|
||||
"react-loadable-ssr-addon-v5-slorber": "^1.0.1",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-config": "^5.1.1",
|
||||
"react-router-dom": "^5.2.0",
|
||||
|
@ -105,15 +102,16 @@
|
|||
"serve-handler": "^6.1.3",
|
||||
"shelljs": "^0.8.4",
|
||||
"std-env": "^2.2.1",
|
||||
"terser-webpack-plugin": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"terser-webpack-plugin": "^5.1.1",
|
||||
"tslib": "^2.1.0",
|
||||
"update-notifier": "^5.1.0",
|
||||
"url-loader": "^4.1.1",
|
||||
"wait-on": "^5.2.1",
|
||||
"webpack": "^4.44.1",
|
||||
"webpack": "^5.28.0",
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"webpack-merge": "^4.2.2",
|
||||
"webpack-merge": "^5.7.3",
|
||||
"webpackbar": "^5.0.0-3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
|
|
@ -64,12 +64,6 @@ function getTransformOptions(isServer: boolean): TransformOptions {
|
|||
isServer
|
||||
? require.resolve('babel-plugin-dynamic-import-node')
|
||||
: require.resolve('@babel/plugin-syntax-dynamic-import'),
|
||||
// Optional chaining and nullish coalescing are supported in @babel/preset-env,
|
||||
// but not yet supported in webpack due to support missing from acorn.
|
||||
// These can be removed once we bumped to webpack 5.
|
||||
// See https://github.com/facebook/docusaurus/issues/2908
|
||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||
require.resolve('@babel/plugin-proposal-nullish-coalescing-operator'),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
|||
import {StaticRouter} from 'react-router-dom';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import {Helmet} from 'react-helmet';
|
||||
import {getBundles} from 'react-loadable-ssr-addon';
|
||||
import {getBundles} from 'react-loadable-ssr-addon-v5-slorber';
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
import {minify} from 'html-minifier-terser';
|
||||
|
|
|
@ -9,8 +9,8 @@ import chalk from 'chalk';
|
|||
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import ReactLoadableSSRAddon from 'react-loadable-ssr-addon';
|
||||
import {Configuration, Plugin} from 'webpack';
|
||||
import ReactLoadableSSRAddon from 'react-loadable-ssr-addon-v5-slorber';
|
||||
import {Configuration} from 'webpack';
|
||||
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
|
||||
import merge from 'webpack-merge';
|
||||
import {STATIC_DIR_NAME} from '../constants';
|
||||
|
@ -21,9 +21,9 @@ import {BuildCLIOptions, Props} from '@docusaurus/types';
|
|||
import createClientConfig from '../webpack/client';
|
||||
import createServerConfig from '../webpack/server';
|
||||
import {
|
||||
compile,
|
||||
applyConfigureWebpack,
|
||||
applyConfigurePostCss,
|
||||
applyConfigureWebpack,
|
||||
compile,
|
||||
} from '../webpack/utils';
|
||||
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
|
||||
import {loadI18n} from '../server/i18n';
|
||||
|
@ -44,15 +44,14 @@ export default async function build(
|
|||
isLastLocale: boolean;
|
||||
}) {
|
||||
try {
|
||||
const result = await buildLocale({
|
||||
// console.log(chalk.green(`Site successfully built in locale=${locale}`));
|
||||
return await buildLocale({
|
||||
siteDir,
|
||||
locale,
|
||||
cliOptions,
|
||||
forceTerminate,
|
||||
isLastLocale,
|
||||
});
|
||||
// console.log(chalk.green(`Site successfully built in locale=${locale}`));
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.error(`error building locale=${locale}`);
|
||||
throw e;
|
||||
|
@ -146,7 +145,7 @@ async function buildLocale({
|
|||
new ReactLoadableSSRAddon({
|
||||
filename: clientManifestPath,
|
||||
}),
|
||||
].filter(Boolean) as Plugin[],
|
||||
].filter(Boolean),
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -160,7 +159,7 @@ async function buildLocale({
|
|||
});
|
||||
|
||||
const staticDir = path.resolve(siteDir, STATIC_DIR_NAME);
|
||||
if (fs.existsSync(staticDir)) {
|
||||
if (await fs.pathExists(staticDir)) {
|
||||
serverConfig = merge(serverConfig, {
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
|
@ -200,12 +199,12 @@ async function buildLocale({
|
|||
|
||||
// Make sure generated client-manifest is cleaned first so we don't reuse
|
||||
// the one from previous builds.
|
||||
if (fs.existsSync(clientManifestPath)) {
|
||||
fs.unlinkSync(clientManifestPath);
|
||||
if (await fs.pathExists(clientManifestPath)) {
|
||||
await fs.unlink(clientManifestPath);
|
||||
}
|
||||
|
||||
// Run webpack to build JS bundle (client) and static html files (server).
|
||||
const finalCompileResult = await compile([clientConfig, serverConfig]);
|
||||
await compile([clientConfig, serverConfig]);
|
||||
|
||||
// Remove server.bundle.js because it is not needed.
|
||||
if (
|
||||
|
@ -214,11 +213,9 @@ async function buildLocale({
|
|||
typeof serverConfig.output.filename === 'string'
|
||||
) {
|
||||
const serverBundle = path.join(outDir, serverConfig.output.filename);
|
||||
fs.pathExists(serverBundle).then((exist) => {
|
||||
if (exist) {
|
||||
fs.unlink(serverBundle);
|
||||
}
|
||||
});
|
||||
if (await fs.pathExists(serverBundle)) {
|
||||
await fs.unlink(serverBundle);
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin Lifecycle - postBuild.
|
||||
|
@ -227,7 +224,7 @@ async function buildLocale({
|
|||
if (!plugin.postBuild) {
|
||||
return;
|
||||
}
|
||||
await plugin.postBuild({...props, stats: finalCompileResult});
|
||||
await plugin.postBuild(props);
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ import {debounce} from 'lodash';
|
|||
import openBrowser from 'react-dev-utils/openBrowser';
|
||||
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
|
||||
import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';
|
||||
import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
|
||||
// import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
|
||||
import evalSourceMapMiddleware from '../webpack/react-dev-utils-webpack5/evalSourceMapMiddleware';
|
||||
import webpack from 'webpack';
|
||||
import WebpackDevServer from 'webpack-dev-server';
|
||||
import merge from 'webpack-merge';
|
||||
|
@ -191,16 +192,12 @@ export default async function start(
|
|||
baseUrl,
|
||||
express.static(path.resolve(siteDir, STATIC_DIR_NAME)),
|
||||
);
|
||||
|
||||
// This lets us fetch source contents from webpack for the error overlay.
|
||||
app.use(evalSourceMapMiddleware(server));
|
||||
// This lets us open files from the runtime error overlay.
|
||||
app.use(errorOverlayMiddleware());
|
||||
|
||||
// TODO: add plugins beforeDevServer and afterDevServer hook
|
||||
},
|
||||
},
|
||||
...config.devServer,
|
||||
};
|
||||
const compiler = webpack(config);
|
||||
if (process.env.E2E_TEST) {
|
||||
|
@ -213,6 +210,7 @@ export default async function start(
|
|||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
const devServer = new WebpackDevServer(compiler, devServerConfig);
|
||||
devServer.listen(port, host, (err) => {
|
||||
if (err) {
|
||||
|
|
|
@ -9,6 +9,10 @@ export const NODE_MAJOR_VERSION = parseInt(
|
|||
process.versions.node.split('.')[0],
|
||||
10,
|
||||
);
|
||||
export const NODE_MINOR_VERSION = parseInt(
|
||||
process.versions.node.split('.')[1],
|
||||
10,
|
||||
);
|
||||
|
||||
// Can be overridden with cli option --out-dir
|
||||
export const DEFAULT_BUILD_DIR_NAME = 'build';
|
||||
|
|
|
@ -325,6 +325,7 @@ ${Object.keys(registry)
|
|||
const props: Props = {
|
||||
siteConfig,
|
||||
siteConfigPath,
|
||||
siteMetadata,
|
||||
siteDir,
|
||||
outDir,
|
||||
baseUrl,
|
||||
|
|
|
@ -84,6 +84,12 @@ describe('base webpack config', () => {
|
|||
baseUrl: '',
|
||||
generatedFilesDir: '',
|
||||
routesPaths: '',
|
||||
i18n: {
|
||||
currentLocale: 'en',
|
||||
},
|
||||
siteMetadata: {
|
||||
docusaurusVersion: '2.0.0-alpha.70',
|
||||
},
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('webpack dev config', () => {
|
|||
const props = await loadSetup('simple');
|
||||
const config = createClientConfig(props);
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
||||
test('custom', async () => {
|
||||
|
@ -24,6 +24,6 @@ describe('webpack dev config', () => {
|
|||
const props = await loadSetup('custom');
|
||||
const config = createClientConfig(props);
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ describe('webpack production config', () => {
|
|||
const props = await loadSetup('simple');
|
||||
const config = createServerConfig({props});
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
||||
test('custom', async () => {
|
||||
|
@ -24,6 +24,6 @@ describe('webpack production config', () => {
|
|||
const props = await loadSetup('custom');
|
||||
const config = createServerConfig({props});
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import {
|
||||
// @ts-expect-error: seems it's not in the typedefs???
|
||||
validate,
|
||||
Configuration,
|
||||
} from 'webpack';
|
||||
import {validate, Configuration} from 'webpack';
|
||||
import path from 'path';
|
||||
|
||||
import {
|
||||
|
@ -55,7 +51,7 @@ describe('extending generated webpack config', () => {
|
|||
},
|
||||
});
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
||||
test('webpack-merge with user webpack config object', async () => {
|
||||
|
@ -83,7 +79,7 @@ describe('extending generated webpack config', () => {
|
|||
},
|
||||
});
|
||||
const errors = validate(config);
|
||||
expect(errors.length).toBe(0);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
||||
test('webpack-merge with custom strategy', async () => {
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
|
||||
import fs from 'fs-extra';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import PnpWebpackPlugin from 'pnp-webpack-plugin';
|
||||
import path from 'path';
|
||||
import {Configuration, Loader} from 'webpack';
|
||||
import {Configuration} from 'webpack';
|
||||
import {Props} from '@docusaurus/types';
|
||||
import {
|
||||
getBabelLoader,
|
||||
getCacheLoader,
|
||||
getJSLoader,
|
||||
getStyleLoaders,
|
||||
getFileLoaderUtils,
|
||||
getCustomBabelConfigFilePath,
|
||||
|
@ -63,8 +61,14 @@ export function createBaseConfig(
|
|||
isServer: boolean,
|
||||
minify: boolean = true,
|
||||
): Configuration {
|
||||
const {outDir, siteDir, baseUrl, generatedFilesDir, routesPaths} = props;
|
||||
|
||||
const {
|
||||
outDir,
|
||||
siteDir,
|
||||
baseUrl,
|
||||
generatedFilesDir,
|
||||
routesPaths,
|
||||
siteMetadata,
|
||||
} = props;
|
||||
const totalPages = routesPaths.length;
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const minimizeEnabled = minify && isProd && !isServer;
|
||||
|
@ -72,11 +76,32 @@ export function createBaseConfig(
|
|||
|
||||
const fileLoaderUtils = getFileLoaderUtils();
|
||||
|
||||
const name = isServer ? 'server' : 'client';
|
||||
const mode = isProd ? 'production' : 'development';
|
||||
|
||||
return {
|
||||
mode: isProd ? 'production' : 'development',
|
||||
mode,
|
||||
name,
|
||||
cache: {
|
||||
// TODO temporary env variable to reduce risk of Webpack 5 release
|
||||
// maybe expose an official api, once this is solved? https://github.com/webpack/webpack/issues/13034
|
||||
type:
|
||||
(process.env.DOCUSAURUS_WEBPACK_CACHE_TYPE as 'filesystem') ||
|
||||
'filesystem',
|
||||
// Can we share the same cache across locales?
|
||||
// Exploring that question at https://github.com/webpack/webpack/issues/13034
|
||||
// name: `${name}-${mode}`,
|
||||
name: `${name}-${mode}-${props.i18n.currentLocale}`,
|
||||
version: siteMetadata.docusaurusVersion,
|
||||
buildDependencies: {
|
||||
// When one of dependencies change, cache is invalidated
|
||||
config: [
|
||||
__filename,
|
||||
path.join(__dirname, isServer ? 'server.js' : 'client.js'),
|
||||
],
|
||||
},
|
||||
},
|
||||
output: {
|
||||
// Use future version of asset emitting logic, which allows freeing memory of assets after emitting.
|
||||
futureEmitAssets: true,
|
||||
pathinfo: false,
|
||||
path: outDir,
|
||||
filename: isProd ? 'assets/js/[name].[contenthash:8].js' : '[name].js',
|
||||
|
@ -89,8 +114,9 @@ export function createBaseConfig(
|
|||
performance: {
|
||||
hints: false,
|
||||
},
|
||||
devtool: isProd ? false : 'cheap-module-eval-source-map',
|
||||
devtool: isProd ? undefined : 'eval-cheap-module-source-map',
|
||||
resolve: {
|
||||
unsafeCache: false, // not enabled, does not seem to improve perf much
|
||||
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
|
||||
symlinks: true,
|
||||
roots: [
|
||||
|
@ -121,10 +147,8 @@ export function createBaseConfig(
|
|||
'node_modules',
|
||||
path.resolve(fs.realpathSync(process.cwd()), 'node_modules'),
|
||||
],
|
||||
plugins: [PnpWebpackPlugin],
|
||||
},
|
||||
resolveLoader: {
|
||||
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
||||
modules: ['node_modules', path.join(siteDir, 'node_modules')],
|
||||
},
|
||||
optimization: {
|
||||
|
@ -137,7 +161,7 @@ export function createBaseConfig(
|
|||
splitChunks: isServer
|
||||
? false
|
||||
: {
|
||||
// Since the chunk name includes all origin chunk names it’s recommended for production builds with long term caching to NOT include [name] in the filenames
|
||||
// Since the chunk name includes all origin chunk names it's recommended for production builds with long term caching to NOT include [name] in the filenames
|
||||
name: false,
|
||||
cacheGroups: {
|
||||
// disable the built-in cacheGroups
|
||||
|
@ -153,7 +177,7 @@ export function createBaseConfig(
|
|||
// See https://github.com/facebook/docusaurus/issues/2006
|
||||
styles: {
|
||||
name: 'styles',
|
||||
test: /\.css$/,
|
||||
type: 'css/mini-extract',
|
||||
chunks: `all`,
|
||||
enforce: true,
|
||||
priority: 50,
|
||||
|
@ -172,9 +196,11 @@ export function createBaseConfig(
|
|||
test: /\.(j|t)sx?$/,
|
||||
exclude: excludeJS,
|
||||
use: [
|
||||
getCacheLoader(isServer),
|
||||
getBabelLoader(isServer, getCustomBabelConfigFilePath(siteDir)),
|
||||
].filter(Boolean) as Loader[],
|
||||
getJSLoader({
|
||||
isServer,
|
||||
babelOptions: getCustomBabelConfigFilePath(siteDir),
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
test: CSS_REGEX,
|
||||
|
@ -191,7 +217,7 @@ export function createBaseConfig(
|
|||
use: getStyleLoaders(isServer, {
|
||||
modules: {
|
||||
localIdentName: isProd
|
||||
? `[local]_[hash:base64:4]`
|
||||
? `[local]_[contenthash:base64:4]`
|
||||
: `[local]_[path]`,
|
||||
exportOnlyLocals: isServer,
|
||||
},
|
||||
|
|
|
@ -24,10 +24,14 @@ export default function createClientConfig(
|
|||
const config = createBaseConfig(props, false, minify);
|
||||
|
||||
const clientConfig = merge(config, {
|
||||
// target: 'browserslist', // useless, disabled on purpose (errors on existing sites with no browserslist cfg)
|
||||
entry: [
|
||||
// Instead of the default WebpackDevServer client, we use a custom one
|
||||
// like CRA to bring better experience.
|
||||
!isProd && require.resolve('react-dev-utils/webpackHotDevClient'),
|
||||
// note: the one in ./dev is modified to work with Docusaurus
|
||||
// !isProd && require.resolve('react-dev-utils/hotDevServer.js'),
|
||||
!isProd &&
|
||||
require.resolve('./react-dev-utils-webpack5/webpackHotDevClient.js'),
|
||||
path.resolve(__dirname, '../client/clientEntry.js'),
|
||||
].filter(Boolean) as string[],
|
||||
optimization: {
|
||||
|
@ -56,10 +60,6 @@ export default function createClientConfig(
|
|||
),
|
||||
);
|
||||
|
||||
stats.toJson('errors-only').errors.forEach((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -15,8 +15,10 @@ class ChunkAssetPlugin {
|
|||
/* 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" */
|
||||
For example: if you have a chunk named "my-chunk-name" that will map to "/publicPath/0a84b5e7.c8e35c7a.js" as its corresponding output path
|
||||
__webpack_require__.gca("my-chunk-name") will return "/publicPath/0a84b5e7.c8e35c7a.js"
|
||||
"gca" stands for "get chunk asset"
|
||||
*/
|
||||
mainTemplate.hooks.requireExtensions.tap(pluginName, (source, chunk) => {
|
||||
const chunkIdToName = chunk.getChunkMaps(false).name;
|
||||
const chunkNameToId = Object.create(null);
|
||||
|
@ -25,16 +27,18 @@ class ChunkAssetPlugin {
|
|||
chunkNameToId[chunkName] = chunkId;
|
||||
});
|
||||
const buf = [source];
|
||||
buf.push('');
|
||||
buf.push('// function to get chunk assets');
|
||||
buf.push('// function to get chunk asset');
|
||||
buf.push(
|
||||
// If chunkName is passed, we convert it to chunk id
|
||||
// Note that jsonpScriptSrc is an internal webpack function
|
||||
`${
|
||||
mainTemplate.requireFn
|
||||
}.gca = function(chunkId) { chunkId = ${JSON.stringify(
|
||||
// If chunkName is passed, we convert it to chunk asset url
|
||||
// .p => public path url ("/" or "/baseUrl/")
|
||||
// .u(chunkId) => chunk asset url ("assets/js/x63b64xd.contentHash.js")
|
||||
// not sure where this is documented, but this link was helpful: https://programmer.help/blogs/5d68849083e1a.html
|
||||
//
|
||||
// Note: __webpack_require__.gca() is called in docusaurus.ts for prefetching
|
||||
// Note: we previously used jsonpScriptSrc (Webpack 4)
|
||||
`__webpack_require__.gca = function(chunkId) { chunkId = ${JSON.stringify(
|
||||
chunkNameToId,
|
||||
)}[chunkId]||chunkId; return jsonpScriptSrc(chunkId); };`,
|
||||
)}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`,
|
||||
);
|
||||
return Template.asString(buf);
|
||||
});
|
||||
|
|
|
@ -27,22 +27,13 @@
|
|||
|
||||
// Forked from https://github.com/johnagan/clean-webpack-plugin
|
||||
// Modified to optimize performance for Docusaurus specific use case
|
||||
// More context: https://github.com/facebook/docusaurus/pull/1839
|
||||
|
||||
import {Compiler, Stats} from 'webpack';
|
||||
import path from 'path';
|
||||
import {sync as delSync} from 'del';
|
||||
|
||||
export interface Options {
|
||||
/** @deprecated */
|
||||
allowExternal?: unknown;
|
||||
|
||||
/**
|
||||
* Simulate the removal of files
|
||||
*
|
||||
* default: false
|
||||
*/
|
||||
dry?: boolean;
|
||||
|
||||
/**
|
||||
* Write Logs to Console
|
||||
* (Always enabled when dry is true)
|
||||
|
@ -74,71 +65,19 @@ export interface Options {
|
|||
* default: ['**\/*']
|
||||
*/
|
||||
cleanOnceBeforeBuildPatterns?: string[];
|
||||
|
||||
/**
|
||||
* Removes files after every build (including watch mode) that match this pattern.
|
||||
* Used for files that are not created directly by Webpack.
|
||||
*
|
||||
* Use !negative patterns to exclude files
|
||||
*
|
||||
* default: disabled
|
||||
*/
|
||||
cleanAfterEveryBuildPatterns?: string[];
|
||||
|
||||
/**
|
||||
* Allow clean patterns outside of process.cwd()
|
||||
*
|
||||
* requires dry option to be explicitly set
|
||||
*
|
||||
* default: false
|
||||
*/
|
||||
dangerouslyAllowCleanPatternsOutsideProject?: boolean;
|
||||
}
|
||||
|
||||
class CleanWebpackPlugin {
|
||||
private readonly dry: boolean;
|
||||
private readonly verbose: boolean;
|
||||
private readonly cleanStaleWebpackAssets: boolean;
|
||||
private readonly protectWebpackAssets: boolean;
|
||||
private readonly cleanAfterEveryBuildPatterns: string[];
|
||||
private readonly cleanOnceBeforeBuildPatterns: string[];
|
||||
private readonly dangerouslyAllowCleanPatternsOutsideProject: boolean;
|
||||
private currentAssets: string[];
|
||||
private initialClean: boolean;
|
||||
private outputPath: string;
|
||||
|
||||
constructor(options: Options = {}) {
|
||||
if (typeof options !== 'object' || Array.isArray(options) === true) {
|
||||
throw new Error(`clean-webpack-plugin only accepts an options object. See:
|
||||
https://github.com/johnagan/clean-webpack-plugin#options-and-defaults-optional`);
|
||||
}
|
||||
|
||||
if (options.allowExternal) {
|
||||
throw new Error(
|
||||
'clean-webpack-plugin: `allowExternal` option no longer supported. Use `dangerouslyAllowCleanPatternsOutsideProject`',
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
options.dangerouslyAllowCleanPatternsOutsideProject === true &&
|
||||
options.dry !== true &&
|
||||
options.dry !== false
|
||||
) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
'clean-webpack-plugin: dangerouslyAllowCleanPatternsOutsideProject requires dry: false to be explicitly set. Enabling dry mode',
|
||||
);
|
||||
}
|
||||
|
||||
this.dangerouslyAllowCleanPatternsOutsideProject =
|
||||
options.dangerouslyAllowCleanPatternsOutsideProject === true || false;
|
||||
|
||||
this.dry =
|
||||
options.dry === true || options.dry === false
|
||||
? options.dry
|
||||
: this.dangerouslyAllowCleanPatternsOutsideProject === true || false;
|
||||
|
||||
this.verbose = this.dry === true || options.verbose === true || false;
|
||||
this.verbose = options.verbose === true || false;
|
||||
|
||||
this.cleanStaleWebpackAssets =
|
||||
options.cleanStaleWebpackAssets === true ||
|
||||
|
@ -152,12 +91,6 @@ class CleanWebpackPlugin {
|
|||
? options.protectWebpackAssets
|
||||
: true;
|
||||
|
||||
this.cleanAfterEveryBuildPatterns = Array.isArray(
|
||||
options.cleanAfterEveryBuildPatterns,
|
||||
)
|
||||
? options.cleanAfterEveryBuildPatterns
|
||||
: [];
|
||||
|
||||
this.cleanOnceBeforeBuildPatterns = Array.isArray(
|
||||
options.cleanOnceBeforeBuildPatterns,
|
||||
)
|
||||
|
@ -194,34 +127,17 @@ class CleanWebpackPlugin {
|
|||
|
||||
this.outputPath = compiler.options.output.path;
|
||||
|
||||
/**
|
||||
* webpack 4+ comes with a new plugin system.
|
||||
*
|
||||
* Check for hooks in-order to support old plugin system
|
||||
*/
|
||||
const {hooks} = compiler;
|
||||
|
||||
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
|
||||
if (hooks) {
|
||||
hooks.compile.tap('clean-webpack-plugin', () => {
|
||||
this.handleInitial();
|
||||
});
|
||||
} else {
|
||||
compiler.plugin('compile', () => {
|
||||
this.handleInitial();
|
||||
});
|
||||
}
|
||||
hooks.compile.tap('clean-webpack-plugin', () => {
|
||||
this.handleInitial();
|
||||
});
|
||||
}
|
||||
|
||||
if (hooks) {
|
||||
hooks.done.tap('clean-webpack-plugin', (stats) => {
|
||||
this.handleDone(stats);
|
||||
});
|
||||
} else {
|
||||
compiler.plugin('done', (stats) => {
|
||||
this.handleDone(stats);
|
||||
});
|
||||
}
|
||||
hooks.done.tap('clean-webpack-plugin', (stats) => {
|
||||
this.handleDone(stats);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,13 +174,10 @@ class CleanWebpackPlugin {
|
|||
* Fetch Webpack's output asset files
|
||||
*/
|
||||
const statsAssets =
|
||||
stats.toJson(
|
||||
{
|
||||
all: false,
|
||||
assets: true,
|
||||
},
|
||||
true,
|
||||
).assets || [];
|
||||
stats.toJson({
|
||||
all: false,
|
||||
assets: true,
|
||||
}).assets || [];
|
||||
const assets = statsAssets.map((asset: {name: string}) => {
|
||||
return asset.name;
|
||||
});
|
||||
|
@ -275,9 +188,7 @@ class CleanWebpackPlugin {
|
|||
* (relies on del's cwd: outputPath option)
|
||||
*/
|
||||
const staleFiles = this.currentAssets.filter((previousAsset) => {
|
||||
const assetCurrent = assets.includes(previousAsset) === false;
|
||||
|
||||
return assetCurrent;
|
||||
return assets.includes(previousAsset) === false;
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -294,13 +205,6 @@ class CleanWebpackPlugin {
|
|||
removePatterns.push(...staleFiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove cleanAfterEveryBuildPatterns
|
||||
*/
|
||||
if (this.cleanAfterEveryBuildPatterns.length !== 0) {
|
||||
removePatterns.push(...this.cleanAfterEveryBuildPatterns);
|
||||
}
|
||||
|
||||
if (removePatterns.length !== 0) {
|
||||
this.removeFiles(removePatterns);
|
||||
}
|
||||
|
@ -309,10 +213,10 @@ class CleanWebpackPlugin {
|
|||
removeFiles(patterns: string[]): void {
|
||||
try {
|
||||
const deleted = delSync(patterns, {
|
||||
force: this.dangerouslyAllowCleanPatternsOutsideProject,
|
||||
force: false,
|
||||
// Change context to build directory
|
||||
cwd: this.outputPath,
|
||||
dryRun: this.dry,
|
||||
dryRun: false,
|
||||
dot: true,
|
||||
ignore: this.protectWebpackAssets ? this.currentAssets : [],
|
||||
});
|
||||
|
@ -324,15 +228,13 @@ class CleanWebpackPlugin {
|
|||
deleted.forEach((file) => {
|
||||
const filename = path.relative(process.cwd(), file);
|
||||
|
||||
const message = this.dry ? 'dry' : 'removed';
|
||||
|
||||
/**
|
||||
* Use console.warn over .log
|
||||
* https://github.com/webpack/webpack/issues/1904
|
||||
* https://github.com/johnagan/clean-webpack-plugin/issues/11
|
||||
*/
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`clean-webpack-plugin: ${message} ${filename}`);
|
||||
console.warn(`clean-webpack-plugin: removed ${filename}`);
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
const WebpackBar = require('webpackbar');
|
||||
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
|
||||
|
||||
function showError(arr) {
|
||||
console.log(`\n\n${arr.join('')}`);
|
||||
}
|
||||
|
||||
class LogPlugin extends WebpackBar {
|
||||
apply(compiler) {
|
||||
super.apply(compiler);
|
||||
|
||||
compiler.hooks.done.tap('WebpackNiceLog', (stats) => {
|
||||
if (stats.hasErrors()) {
|
||||
const messages = formatWebpackMessages(
|
||||
stats.toJson('errors-only', true),
|
||||
);
|
||||
if (messages.errors.length) {
|
||||
showError(messages.errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LogPlugin;
|
35
packages/docusaurus/src/webpack/plugins/LogPlugin.ts
Normal file
35
packages/docusaurus/src/webpack/plugins/LogPlugin.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
import WebpackBar from 'webpackbar';
|
||||
import {Compiler} from 'webpack';
|
||||
// import formatWebpackMessages from 'react-dev-utils/formatWebpackMessages';
|
||||
import formatWebpackMessages from '../react-dev-utils-webpack5/formatWebpackMessages';
|
||||
|
||||
function showError(arr) {
|
||||
console.log(`\n\n${arr.join('\n')}`);
|
||||
}
|
||||
|
||||
export default class LogPlugin extends WebpackBar {
|
||||
apply(compiler: Compiler): void {
|
||||
super.apply(compiler);
|
||||
|
||||
// TODO can't this be done in compile(configs) alongside the warnings???
|
||||
compiler.hooks.done.tap('DocusaurusLogPlugin', (stats) => {
|
||||
if (stats.hasErrors()) {
|
||||
const errorsWarnings = stats.toJson('errors-warnings');
|
||||
|
||||
// TODO do we really want to keep this legacy logic?
|
||||
// let's wait and see how the react-dev-utils support Webpack5
|
||||
// we probably want to print the error stacktraces here
|
||||
const messages = formatWebpackMessages(errorsWarnings);
|
||||
if (messages.errors.length) {
|
||||
showError(messages.errors);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
This is a temporary copy of
|
||||
|
||||
CRA / react-dev-utils does not support Webpack 5 yet
|
||||
|
||||
https://github.com/facebook/create-react-app/issues/9994
|
||||
|
||||
This folder is a temporary copy of some react-dev-utils code to which we made some changes to support Webpack 5 without warnings
|
||||
|
||||
TODO remove this folder once Webpack 5 is supported (https://github.com/facebook/create-react-app/issues/9994)
|
||||
|
||||
The comment `// modified for Docusaurus` is added near the modified elements
|
57
packages/docusaurus/src/webpack/react-dev-utils-webpack5/evalSourceMapMiddleware.js
vendored
Normal file
57
packages/docusaurus/src/webpack/react-dev-utils-webpack5/evalSourceMapMiddleware.js
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
/*
|
||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
||||
* the above copyright header must be preserved for license compliance.
|
||||
*/
|
||||
|
||||
/*
|
||||
Implementation based on comment: https://github.com/facebook/create-react-app/issues/9994#issuecomment-811289191
|
||||
*/
|
||||
|
||||
function base64SourceMap(source) {
|
||||
const base64 = Buffer.from(JSON.stringify(source.map()), 'utf8').toString(
|
||||
'base64',
|
||||
);
|
||||
return `data:application/json;charset=utf-8;base64,${base64}`;
|
||||
}
|
||||
|
||||
// modified for Docusaurus => remove webpack 5 deprecation warnings
|
||||
// See https://github.com/facebook/create-react-app/issues/9994#issuecomment-811289191
|
||||
function getSourceById(server, id) {
|
||||
const module = Array.from(server._stats.compilation.modules).find(
|
||||
(m) => server._stats.compilation.chunkGraph.getModuleId(m) == id,
|
||||
);
|
||||
return module.originalSource();
|
||||
}
|
||||
|
||||
/*
|
||||
* Middleware responsible for retrieving a generated source
|
||||
* Receives a webpack internal url: "webpack-internal:///<module-id>"
|
||||
* Returns a generated source: "<source-text><sourceMappingURL><sourceURL>"
|
||||
*
|
||||
* Based on EvalSourceMapDevToolModuleTemplatePlugin.js
|
||||
*/
|
||||
module.exports = function createEvalSourceMapMiddleware(server) {
|
||||
return function handleWebpackInternalMiddleware(req, res, next) {
|
||||
if (req.url.startsWith('/__get-internal-source')) {
|
||||
const fileName = req.query.fileName;
|
||||
const id = fileName.match(/webpack-internal:\/\/\/(.+)/)[1];
|
||||
if (!id || !server._stats) {
|
||||
next();
|
||||
}
|
||||
|
||||
const source = getSourceById(server, id);
|
||||
const sourceMapURL = `//# sourceMappingURL=${base64SourceMap(source)}`;
|
||||
const sourceURL = `//# sourceURL=webpack-internal:///${module.id}`;
|
||||
res.end(`${source.source()}\n${sourceMapURL}\n${sourceURL}`);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
};
|
138
packages/docusaurus/src/webpack/react-dev-utils-webpack5/formatWebpackMessages.js
vendored
Normal file
138
packages/docusaurus/src/webpack/react-dev-utils-webpack5/formatWebpackMessages.js
vendored
Normal file
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
/*
|
||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
||||
* the above copyright header must be preserved for license compliance.
|
||||
*/
|
||||
|
||||
/*
|
||||
Implementation has been copied from https://github.com/facebook/create-react-app/pull/10656
|
||||
*/
|
||||
|
||||
const friendlySyntaxErrorLabel = 'Syntax error:';
|
||||
|
||||
function isLikelyASyntaxError(message) {
|
||||
return message.indexOf(friendlySyntaxErrorLabel) !== -1;
|
||||
}
|
||||
|
||||
// Cleans up webpack error messages.
|
||||
function formatMessage(message) {
|
||||
let lines = [];
|
||||
|
||||
// modified for Docusaurus => see https://github.com/facebook/create-react-app/pull/10656
|
||||
if (typeof message === 'string') {
|
||||
lines = message.split('\n');
|
||||
} else if ('message' in message) {
|
||||
lines = message['message'].split('\n');
|
||||
} else if (Array.isArray(message)) {
|
||||
message.forEach((message) => {
|
||||
if ('message' in message) {
|
||||
lines = message['message'].split('\n');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Strip webpack-added headers off errors/warnings
|
||||
// https://github.com/webpack/webpack/blob/master/lib/ModuleError.js
|
||||
lines = lines.filter((line) => !/Module [A-z ]+\(from/.test(line));
|
||||
|
||||
// Transform parsing error into syntax error
|
||||
// TODO: move this to our ESLint formatter?
|
||||
lines = lines.map((line) => {
|
||||
const parsingError = /Line (\d+):(?:(\d+):)?\s*Parsing error: (.+)$/.exec(
|
||||
line,
|
||||
);
|
||||
if (!parsingError) {
|
||||
return line;
|
||||
}
|
||||
const [, errorLine, errorColumn, errorMessage] = parsingError;
|
||||
return `${friendlySyntaxErrorLabel} ${errorMessage} (${errorLine}:${errorColumn})`;
|
||||
});
|
||||
|
||||
message = lines.join('\n');
|
||||
// Smoosh syntax errors (commonly found in CSS)
|
||||
message = message.replace(
|
||||
/SyntaxError\s+\((\d+):(\d+)\)\s*(.+?)\n/g,
|
||||
`${friendlySyntaxErrorLabel} $3 ($1:$2)\n`,
|
||||
);
|
||||
// Clean up export errors
|
||||
message = message.replace(
|
||||
/^.*export '(.+?)' was not found in '(.+?)'.*$/gm,
|
||||
`Attempted import error: '$1' is not exported from '$2'.`,
|
||||
);
|
||||
message = message.replace(
|
||||
/^.*export 'default' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
|
||||
`Attempted import error: '$2' does not contain a default export (imported as '$1').`,
|
||||
);
|
||||
message = message.replace(
|
||||
/^.*export '(.+?)' \(imported as '(.+?)'\) was not found in '(.+?)'.*$/gm,
|
||||
`Attempted import error: '$1' is not exported from '$3' (imported as '$2').`,
|
||||
);
|
||||
lines = message.split('\n');
|
||||
|
||||
// Remove leading newline
|
||||
if (lines.length > 2 && lines[1].trim() === '') {
|
||||
lines.splice(1, 1);
|
||||
}
|
||||
// Clean up file name
|
||||
lines[0] = lines[0].replace(/^(.*) \d+:\d+-\d+$/, '$1');
|
||||
|
||||
// Cleans up verbose "module not found" messages for files and packages.
|
||||
if (lines[1] && lines[1].indexOf('Module not found: ') === 0) {
|
||||
lines = [
|
||||
lines[0],
|
||||
lines[1]
|
||||
.replace('Error: ', '')
|
||||
.replace('Module not found: Cannot find file:', 'Cannot find file:'),
|
||||
];
|
||||
}
|
||||
|
||||
// Add helpful message for users trying to use Sass for the first time
|
||||
if (lines[1] && lines[1].match(/Cannot find module.+node-sass/)) {
|
||||
lines[1] = 'To import Sass files, you first need to install node-sass.\n';
|
||||
lines[1] +=
|
||||
'Run `npm install node-sass` or `yarn add node-sass` inside your workspace.';
|
||||
}
|
||||
|
||||
message = lines.join('\n');
|
||||
// Internal stacks are generally useless so we strip them... with the
|
||||
// exception of stacks containing `webpack:` because they're normally
|
||||
// from user code generated by webpack. For more information see
|
||||
// https://github.com/facebook/create-react-app/pull/1050
|
||||
message = message.replace(
|
||||
/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm,
|
||||
'',
|
||||
); // at ... ...:x:y
|
||||
message = message.replace(/^\s*at\s<anonymous>(\n|$)/gm, ''); // at <anonymous>
|
||||
lines = message.split('\n');
|
||||
|
||||
// Remove duplicated newlines
|
||||
lines = lines.filter(
|
||||
(line, index, arr) =>
|
||||
index === 0 ||
|
||||
line.trim() !== '' ||
|
||||
line.trim() !== arr[index - 1].trim(),
|
||||
);
|
||||
|
||||
// Reassemble the message
|
||||
message = lines.join('\n');
|
||||
return message.trim();
|
||||
}
|
||||
|
||||
function formatWebpackMessages(json) {
|
||||
const formattedErrors = json.errors.map(formatMessage);
|
||||
const formattedWarnings = json.warnings.map(formatMessage);
|
||||
const result = {errors: formattedErrors, warnings: formattedWarnings};
|
||||
if (result.errors.some(isLikelyASyntaxError)) {
|
||||
// If there are any syntax errors, show just them.
|
||||
result.errors = result.errors.filter(isLikelyASyntaxError);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = formatWebpackMessages;
|
285
packages/docusaurus/src/webpack/react-dev-utils-webpack5/webpackHotDevClient.js
vendored
Normal file
285
packages/docusaurus/src/webpack/react-dev-utils-webpack5/webpackHotDevClient.js
vendored
Normal file
|
@ -0,0 +1,285 @@
|
|||
/**
|
||||
* Copyright (c) 2015-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.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
/*
|
||||
* THIS FILE IS MODIFIED FOR DOCUSAURUS
|
||||
* the above copyright header must be preserved for license compliance.
|
||||
*/
|
||||
|
||||
// This alternative WebpackDevServer combines the functionality of:
|
||||
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
|
||||
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
|
||||
|
||||
// It only supports their simplest configuration (hot updates on same server).
|
||||
// It makes some opinionated choices on top, like adding a syntax error overlay
|
||||
// that looks similar to our console output. The error overlay is inspired by:
|
||||
// https://github.com/glenjamin/webpack-hot-middleware
|
||||
|
||||
var stripAnsi = require('strip-ansi');
|
||||
var url = require('url');
|
||||
var launchEditorEndpoint = require('react-dev-utils/launchEditorEndpoint'); // modified for Docusaurus
|
||||
var formatWebpackMessages = require('./formatWebpackMessages');
|
||||
var ErrorOverlay = require('react-error-overlay');
|
||||
|
||||
ErrorOverlay.setEditorHandler(function editorHandler(errorLocation) {
|
||||
// Keep this sync with errorOverlayMiddleware.js
|
||||
fetch(
|
||||
launchEditorEndpoint +
|
||||
'?fileName=' +
|
||||
window.encodeURIComponent(errorLocation.fileName) +
|
||||
'&lineNumber=' +
|
||||
window.encodeURIComponent(errorLocation.lineNumber || 1) +
|
||||
'&colNumber=' +
|
||||
window.encodeURIComponent(errorLocation.colNumber || 1),
|
||||
);
|
||||
});
|
||||
|
||||
// We need to keep track of if there has been a runtime error.
|
||||
// Essentially, we cannot guarantee application state was not corrupted by the
|
||||
// runtime error. To prevent confusing behavior, we forcibly reload the entire
|
||||
// application. This is handled below when we are notified of a compile (code
|
||||
// change).
|
||||
// See https://github.com/facebook/create-react-app/issues/3096
|
||||
var hadRuntimeError = false;
|
||||
ErrorOverlay.startReportingRuntimeErrors({
|
||||
onError: function () {
|
||||
hadRuntimeError = true;
|
||||
},
|
||||
filename: '/static/js/bundle.js',
|
||||
});
|
||||
|
||||
if (module.hot && typeof module.hot.dispose === 'function') {
|
||||
module.hot.dispose(function () {
|
||||
// TODO: why do we need this?
|
||||
ErrorOverlay.stopReportingRuntimeErrors();
|
||||
});
|
||||
}
|
||||
|
||||
// Connect to WebpackDevServer via a socket.
|
||||
var connection = new WebSocket(
|
||||
url.format({
|
||||
protocol: window.location.protocol === 'https:' ? 'wss' : 'ws',
|
||||
// modified for Docusaurus => avoid "ReferenceError: process is not defined"
|
||||
hostname: window.location.hostname,
|
||||
port: window.location.port,
|
||||
// Hardcoded in WebpackDevServer
|
||||
pathname: '/sockjs-node',
|
||||
slashes: true,
|
||||
}),
|
||||
);
|
||||
|
||||
// Unlike WebpackDevServer client, we won't try to reconnect
|
||||
// to avoid spamming the console. Disconnect usually happens
|
||||
// when developer stops the server.
|
||||
connection.onclose = function () {
|
||||
if (typeof console !== 'undefined' && typeof console.info === 'function') {
|
||||
console.info(
|
||||
'The development server has disconnected.\nRefresh the page if necessary.',
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Remember some state related to hot module replacement.
|
||||
var isFirstCompilation = true;
|
||||
var mostRecentCompilationHash = null;
|
||||
var hasCompileErrors = false;
|
||||
|
||||
function clearOutdatedErrors() {
|
||||
// Clean up outdated compile errors, if any.
|
||||
if (typeof console !== 'undefined' && typeof console.clear === 'function') {
|
||||
if (hasCompileErrors) {
|
||||
console.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Successful compilation.
|
||||
function handleSuccess() {
|
||||
clearOutdatedErrors();
|
||||
|
||||
var isHotUpdate = !isFirstCompilation;
|
||||
isFirstCompilation = false;
|
||||
hasCompileErrors = false;
|
||||
|
||||
// Attempt to apply hot updates or reload.
|
||||
if (isHotUpdate) {
|
||||
tryApplyUpdates(function onHotUpdateSuccess() {
|
||||
// Only dismiss it when we're sure it's a hot update.
|
||||
// Otherwise it would flicker right before the reload.
|
||||
tryDismissErrorOverlay();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Compilation with warnings (e.g. ESLint).
|
||||
function handleWarnings(warnings) {
|
||||
clearOutdatedErrors();
|
||||
|
||||
var isHotUpdate = !isFirstCompilation;
|
||||
isFirstCompilation = false;
|
||||
hasCompileErrors = false;
|
||||
|
||||
function printWarnings() {
|
||||
// Print warnings to the console.
|
||||
var formatted = formatWebpackMessages({
|
||||
warnings: warnings,
|
||||
errors: [],
|
||||
});
|
||||
|
||||
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
||||
for (var i = 0; i < formatted.warnings.length; i++) {
|
||||
if (i === 5) {
|
||||
console.warn(
|
||||
'There were more warnings in other files.\n' +
|
||||
'You can find a complete log in the terminal.',
|
||||
);
|
||||
break;
|
||||
}
|
||||
console.warn(stripAnsi(formatted.warnings[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printWarnings();
|
||||
|
||||
// Attempt to apply hot updates or reload.
|
||||
if (isHotUpdate) {
|
||||
tryApplyUpdates(function onSuccessfulHotUpdate() {
|
||||
// Only dismiss it when we're sure it's a hot update.
|
||||
// Otherwise it would flicker right before the reload.
|
||||
tryDismissErrorOverlay();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Compilation with errors (e.g. syntax error or missing modules).
|
||||
function handleErrors(errors) {
|
||||
clearOutdatedErrors();
|
||||
|
||||
isFirstCompilation = false;
|
||||
hasCompileErrors = true;
|
||||
|
||||
// "Massage" webpack messages.
|
||||
var formatted = formatWebpackMessages({
|
||||
errors: errors,
|
||||
warnings: [],
|
||||
});
|
||||
|
||||
// Only show the first error.
|
||||
ErrorOverlay.reportBuildError(formatted.errors[0]);
|
||||
|
||||
// Also log them to the console.
|
||||
if (typeof console !== 'undefined' && typeof console.error === 'function') {
|
||||
for (var i = 0; i < formatted.errors.length; i++) {
|
||||
console.error(stripAnsi(formatted.errors[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Do not attempt to reload now.
|
||||
// We will reload on next success instead.
|
||||
}
|
||||
|
||||
function tryDismissErrorOverlay() {
|
||||
if (!hasCompileErrors) {
|
||||
ErrorOverlay.dismissBuildError();
|
||||
}
|
||||
}
|
||||
|
||||
// There is a newer version of the code available.
|
||||
function handleAvailableHash(hash) {
|
||||
// Update last known compilation hash.
|
||||
mostRecentCompilationHash = hash;
|
||||
}
|
||||
|
||||
// Handle messages from the server.
|
||||
connection.onmessage = function (e) {
|
||||
var message = JSON.parse(e.data);
|
||||
switch (message.type) {
|
||||
case 'hash':
|
||||
handleAvailableHash(message.data);
|
||||
break;
|
||||
case 'still-ok':
|
||||
case 'ok':
|
||||
handleSuccess();
|
||||
break;
|
||||
case 'content-changed':
|
||||
// Triggered when a file from `contentBase` changed.
|
||||
window.location.reload();
|
||||
break;
|
||||
case 'warnings':
|
||||
handleWarnings(message.data);
|
||||
break;
|
||||
case 'errors':
|
||||
handleErrors(message.data);
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
|
||||
// Is there a newer version of this code available?
|
||||
function isUpdateAvailable() {
|
||||
/* globals __webpack_hash__ */
|
||||
// __webpack_hash__ is the hash of the current compilation.
|
||||
// It's a global variable injected by webpack.
|
||||
return mostRecentCompilationHash !== __webpack_hash__;
|
||||
}
|
||||
|
||||
// webpack disallows updates in other states.
|
||||
function canApplyUpdates() {
|
||||
return module.hot.status() === 'idle';
|
||||
}
|
||||
|
||||
// Attempt to update code on the fly, fall back to a hard reload.
|
||||
function tryApplyUpdates(onHotUpdateSuccess) {
|
||||
if (!module.hot) {
|
||||
// HotModuleReplacementPlugin is not in webpack configuration.
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isUpdateAvailable() || !canApplyUpdates()) {
|
||||
return;
|
||||
}
|
||||
|
||||
function handleApplyUpdates(err, updatedModules) {
|
||||
// NOTE: This var is injected by Webpack's DefinePlugin, and is a boolean instead of string.
|
||||
// const hasReactRefresh = process.env.FAST_REFRESH;
|
||||
const hasReactRefresh = true; // modified for Docusaurus => avoid "ReferenceError: process is not defined"
|
||||
const wantsForcedReload = err || !updatedModules || hadRuntimeError;
|
||||
// React refresh can handle hot-reloading over errors.
|
||||
if (!hasReactRefresh && wantsForcedReload) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof onHotUpdateSuccess === 'function') {
|
||||
// Maybe we want to do something.
|
||||
onHotUpdateSuccess();
|
||||
}
|
||||
|
||||
if (isUpdateAvailable()) {
|
||||
// While we were updating, there was a new update! Do it again.
|
||||
tryApplyUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
// https://webpack.github.io/docs/hot-module-replacement.html#check
|
||||
var result = module.hot.check(/* autoApply */ true, handleApplyUpdates);
|
||||
|
||||
// // webpack 2 returns a Promise instead of invoking a callback
|
||||
if (result && result.then) {
|
||||
result.then(
|
||||
function (updatedModules) {
|
||||
handleApplyUpdates(null, updatedModules);
|
||||
},
|
||||
function (err) {
|
||||
handleApplyUpdates(err, null);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import {Props} from '@docusaurus/types';
|
|||
import {createBaseConfig} from './base';
|
||||
import WaitPlugin from './plugins/WaitPlugin';
|
||||
import LogPlugin from './plugins/LogPlugin';
|
||||
import {NODE_MAJOR_VERSION, NODE_MINOR_VERSION} from '../constants';
|
||||
|
||||
export default function createServerConfig({
|
||||
props,
|
||||
|
@ -43,6 +44,7 @@ export default function createServerConfig({
|
|||
return ssgPath;
|
||||
});
|
||||
const serverConfig = merge(config, {
|
||||
target: `node${NODE_MAJOR_VERSION}.${NODE_MINOR_VERSION}`,
|
||||
entry: {
|
||||
main: path.resolve(__dirname, '../client/serverEntry.js'),
|
||||
},
|
||||
|
@ -52,7 +54,6 @@ export default function createServerConfig({
|
|||
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
|
||||
globalObject: 'this',
|
||||
},
|
||||
target: 'node',
|
||||
plugins: [
|
||||
// Wait until manifest from client bundle is generated
|
||||
new WaitPlugin({
|
||||
|
|
|
@ -6,20 +6,20 @@
|
|||
*/
|
||||
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import env from 'std-env';
|
||||
import merge from 'webpack-merge';
|
||||
import {
|
||||
mergeWithCustomize,
|
||||
customizeArray,
|
||||
customizeObject,
|
||||
CustomizeRule,
|
||||
} from 'webpack-merge';
|
||||
import webpack, {
|
||||
Configuration,
|
||||
Loader,
|
||||
NewLoader,
|
||||
Plugin,
|
||||
RuleSetRule,
|
||||
Stats,
|
||||
WebpackPluginInstance,
|
||||
} from 'webpack';
|
||||
import fs from 'fs-extra';
|
||||
import TerserPlugin from 'terser-webpack-plugin';
|
||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
||||
import CleanCss from 'clean-css';
|
||||
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||
import path from 'path';
|
||||
import crypto from 'crypto';
|
||||
import chalk from 'chalk';
|
||||
|
@ -28,13 +28,13 @@ import {
|
|||
ConfigureWebpackFn,
|
||||
ConfigurePostCssFn,
|
||||
PostCssOptions,
|
||||
ConfigureWebpackUtils,
|
||||
} from '@docusaurus/types';
|
||||
import CssNanoPreset from '@docusaurus/cssnano-preset';
|
||||
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
|
||||
import {
|
||||
BABEL_CONFIG_FILE_NAME,
|
||||
OUTPUT_STATIC_ASSETS_DIR_NAME,
|
||||
} from '../constants';
|
||||
import {memoize} from 'lodash';
|
||||
|
||||
// Utility method to get style loaders
|
||||
export function getStyleLoaders(
|
||||
|
@ -42,24 +42,36 @@ export function getStyleLoaders(
|
|||
cssOptions: {
|
||||
[key: string]: unknown;
|
||||
} = {},
|
||||
): Loader[] {
|
||||
): RuleSetRule[] {
|
||||
if (isServer) {
|
||||
return [
|
||||
cssOptions.modules
|
||||
? {
|
||||
return cssOptions.modules
|
||||
? [
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
options: cssOptions,
|
||||
}
|
||||
: require.resolve('null-loader'),
|
||||
];
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
// Don't emit CSS files for SSR (previously used null-loader)
|
||||
// See https://github.com/webpack-contrib/mini-css-extract-plugin/issues/90#issuecomment-811991738
|
||||
emit: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
options: cssOptions,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const isProd = process.env.NODE_ENV === 'production';
|
||||
const loaders = [
|
||||
return [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
hmr: !isProd,
|
||||
esModule: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -84,24 +96,6 @@ export function getStyleLoaders(
|
|||
},
|
||||
},
|
||||
];
|
||||
return loaders;
|
||||
}
|
||||
|
||||
export function getCacheLoader(
|
||||
isServer: boolean,
|
||||
cacheOptions?: {[key: string]: unknown},
|
||||
): Loader | null {
|
||||
if (env.ci || env.test) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
loader: require.resolve('cache-loader'),
|
||||
options: {
|
||||
cacheIdentifier: `cache-loader:${cacheLoaderVersion}${isServer}`,
|
||||
...cacheOptions,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getCustomBabelConfigFilePath(
|
||||
|
@ -141,16 +135,50 @@ export function getBabelOptions({
|
|||
}
|
||||
}
|
||||
|
||||
export function getBabelLoader(
|
||||
isServer: boolean,
|
||||
babelOptions?: TransformOptions | string,
|
||||
): Loader {
|
||||
// Name is generic on purpose
|
||||
// we want to support multiple js loader implementations (babel + esbuild)
|
||||
export function getJSLoader({
|
||||
isServer,
|
||||
babelOptions,
|
||||
}: {
|
||||
isServer: boolean;
|
||||
babelOptions?: TransformOptions | string;
|
||||
}): RuleSetRule {
|
||||
return {
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: getBabelOptions({isServer, babelOptions}),
|
||||
};
|
||||
}
|
||||
|
||||
// TODO remove this before end of 2021?
|
||||
const warnBabelLoaderOnce = memoize(function () {
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
'Docusaurus plans to support multiple JS loader strategies (Babel, esbuild...): getBabelLoader(isServer) is now deprecated in favor of getJSLoader({isServer})',
|
||||
),
|
||||
);
|
||||
});
|
||||
const getBabelLoaderDeprecated = function getBabelLoaderDeprecated(
|
||||
isServer: boolean,
|
||||
babelOptions?: TransformOptions | string,
|
||||
) {
|
||||
warnBabelLoaderOnce();
|
||||
return getJSLoader({isServer, babelOptions});
|
||||
};
|
||||
|
||||
// TODO remove this before end of 2021 ?
|
||||
const warnCacheLoaderOnce = memoize(function () {
|
||||
console.warn(
|
||||
chalk.yellow(
|
||||
'Docusaurus uses Webpack 5 and getCacheLoader() usage is now deprecated',
|
||||
),
|
||||
);
|
||||
});
|
||||
function getCacheLoaderDeprecated() {
|
||||
warnCacheLoaderOnce();
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to modify webpack config
|
||||
* @param configureWebpack a webpack config or a function to modify config
|
||||
|
@ -164,15 +192,21 @@ export function applyConfigureWebpack(
|
|||
isServer: boolean,
|
||||
): Configuration {
|
||||
// Export some utility functions
|
||||
const utils = {
|
||||
const utils: ConfigureWebpackUtils = {
|
||||
getStyleLoaders,
|
||||
getCacheLoader,
|
||||
getBabelLoader,
|
||||
getJSLoader,
|
||||
getBabelLoader: getBabelLoaderDeprecated,
|
||||
getCacheLoader: getCacheLoaderDeprecated,
|
||||
};
|
||||
if (typeof configureWebpack === 'function') {
|
||||
const {mergeStrategy, ...res} = configureWebpack(config, isServer, utils);
|
||||
if (res && typeof res === 'object') {
|
||||
return merge.strategy(mergeStrategy ?? {})(config, res);
|
||||
// @ts-expect-error: annoying error due to enums: https://github.com/survivejs/webpack-merge/issues/179
|
||||
const customizeRules: Record<string, CustomizeRule> = mergeStrategy ?? {};
|
||||
return mergeWithCustomize({
|
||||
customizeArray: customizeArray(customizeRules),
|
||||
customizeObject: customizeObject(customizeRules),
|
||||
})(config, res);
|
||||
}
|
||||
}
|
||||
return config;
|
||||
|
@ -182,13 +216,13 @@ export function applyConfigurePostCss(
|
|||
configurePostCss: NonNullable<ConfigurePostCssFn>,
|
||||
config: Configuration,
|
||||
): Configuration {
|
||||
type LocalPostCSSLoader = Loader & {
|
||||
type LocalPostCSSLoader = unknown & {
|
||||
options: {postcssOptions: PostCssOptions};
|
||||
};
|
||||
|
||||
// TODO not ideal heuristic but good enough for our usecase?
|
||||
function isPostCssLoader(loader: Loader): loader is LocalPostCSSLoader {
|
||||
return !!(loader as NewLoader)?.options?.postcssOptions;
|
||||
function isPostCssLoader(loader: unknown): loader is LocalPostCSSLoader {
|
||||
return !!(loader as any)?.options?.postcssOptions;
|
||||
}
|
||||
|
||||
// Does not handle all edge cases, but good enough for now
|
||||
|
@ -206,67 +240,46 @@ export function applyConfigurePostCss(
|
|||
}
|
||||
}
|
||||
|
||||
config.module?.rules.forEach(overridePostCssOptions);
|
||||
config.module?.rules?.forEach(overridePostCssOptions);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
// See https://webpack.js.org/configuration/stats/#statswarningsfilter
|
||||
// @slorber: note sure why we have to re-implement this logic
|
||||
// just know that legacy had this only partially implemented, so completed it
|
||||
type WarningFilter = string | RegExp | ((warning: string) => boolean);
|
||||
function filterWarnings(
|
||||
warningsFilter: WarningFilter[],
|
||||
warnings: string[],
|
||||
): string[] {
|
||||
function isWarningFiltered(warning: string): boolean {
|
||||
return warningsFilter.some((warningFilter) => {
|
||||
if (typeof warningFilter === 'string') {
|
||||
return warning.includes(warningFilter);
|
||||
} else if (warningFilter instanceof RegExp) {
|
||||
return !!warning.match(warningFilter);
|
||||
} else if (warningFilter instanceof Function) {
|
||||
return warningFilter(warning);
|
||||
} else {
|
||||
throw new Error(`Unknown warningFilter type = ${typeof warningFilter}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return warnings.filter((warning) => !isWarningFiltered(warning));
|
||||
}
|
||||
|
||||
export function compile(config: Configuration[]): Promise<Stats.ToJsonOutput> {
|
||||
export function compile(config: Configuration[]): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const compiler = webpack(config);
|
||||
compiler.run((err, stats) => {
|
||||
if (err) {
|
||||
reject(new Error(err.toString()));
|
||||
console.error(err.stack || err);
|
||||
// @ts-expect-error: see https://webpack.js.org/api/node/#error-handling
|
||||
if (err.details) {
|
||||
// @ts-expect-error: see https://webpack.js.org/api/node/#error-handling
|
||||
console.error(err.details);
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
// let plugins consume all the stats
|
||||
const allStats = stats?.toJson('errors-warnings');
|
||||
const errorsWarnings = stats?.toJson('errors-warnings');
|
||||
if (stats?.hasErrors()) {
|
||||
allStats.errors.forEach((e) => {
|
||||
console.error(e);
|
||||
});
|
||||
reject(new Error('Failed to compile with errors.'));
|
||||
}
|
||||
if (stats?.hasWarnings()) {
|
||||
// Custom filtering warnings (see https://github.com/webpack/webpack/issues/7841).
|
||||
let warnings = [...allStats.warnings];
|
||||
|
||||
const warningsFilter = ((config[0].stats as Stats.ToJsonOptionsObject)
|
||||
?.warningsFilter || []) as WarningFilter[];
|
||||
|
||||
if (Array.isArray(warningsFilter)) {
|
||||
warnings = filterWarnings(warningsFilter, warnings);
|
||||
}
|
||||
|
||||
warnings.forEach((warning) => {
|
||||
if (errorsWarnings && stats?.hasWarnings()) {
|
||||
errorsWarnings.warnings?.forEach((warning) => {
|
||||
console.warn(warning);
|
||||
});
|
||||
}
|
||||
resolve(allStats);
|
||||
// Webpack 5 requires calling close() so that persistent caching works
|
||||
// See https://github.com/webpack/webpack.js.org/pull/4775
|
||||
compiler.close((errClose) => {
|
||||
if (errClose) {
|
||||
console.error(
|
||||
chalk.red('Error while closing Webpack compiler', errClose),
|
||||
);
|
||||
reject(errClose);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -275,8 +288,8 @@ type AssetFolder = 'images' | 'files' | 'fonts' | 'medias';
|
|||
|
||||
type FileLoaderUtils = {
|
||||
loaders: {
|
||||
file: (options: {folder: AssetFolder}) => Loader;
|
||||
url: (options: {folder: AssetFolder}) => Loader;
|
||||
file: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||
url: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||
inlineMarkdownImageFileLoader: string;
|
||||
inlineMarkdownLinkFileLoader: string;
|
||||
};
|
||||
|
@ -298,7 +311,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
const fileLoaderFileName = (folder: AssetFolder) =>
|
||||
`${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`;
|
||||
|
||||
const loaders = {
|
||||
const loaders: FileLoaderUtils['loaders'] = {
|
||||
file: (options: {folder: AssetFolder}) => {
|
||||
return {
|
||||
loader: require.resolve(`file-loader`),
|
||||
|
@ -331,19 +344,19 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
)}!`,
|
||||
};
|
||||
|
||||
const rules = {
|
||||
const rules: FileLoaderUtils['rules'] = {
|
||||
/**
|
||||
* Loads image assets, inlines images via a data URI if they are below
|
||||
* the size threshold
|
||||
*/
|
||||
images: (): RuleSetRule => {
|
||||
images: () => {
|
||||
return {
|
||||
use: [loaders.url({folder: 'images'})],
|
||||
test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/,
|
||||
};
|
||||
},
|
||||
|
||||
fonts: (): RuleSetRule => {
|
||||
fonts: () => {
|
||||
return {
|
||||
use: [loaders.url({folder: 'fonts'})],
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
||||
|
@ -354,14 +367,14 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
* Loads audio and video and inlines them via a data URI if they are below
|
||||
* the size threshold
|
||||
*/
|
||||
media: (): RuleSetRule => {
|
||||
media: () => {
|
||||
return {
|
||||
use: [loaders.url({folder: 'medias'})],
|
||||
test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/,
|
||||
};
|
||||
},
|
||||
|
||||
svg: (): RuleSetRule => {
|
||||
svg: () => {
|
||||
return {
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
|
@ -383,7 +396,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
// We don't want to use SVGR loader for non-React source code
|
||||
// ie we don't want to use SVGR for CSS files...
|
||||
issuer: {
|
||||
test: /\.(ts|tsx|js|jsx|md|mdx)$/,
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -393,7 +406,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
|||
};
|
||||
},
|
||||
|
||||
otherAssets: (): RuleSetRule => {
|
||||
otherAssets: () => {
|
||||
return {
|
||||
use: [loaders.file({folder: 'files'})],
|
||||
test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/,
|
||||
|
@ -476,12 +489,12 @@ function getTerserParallel() {
|
|||
return terserParallel;
|
||||
}
|
||||
|
||||
export function getMinimizer(useSimpleCssMinifier = false): Plugin[] {
|
||||
export function getMinimizer(
|
||||
useSimpleCssMinifier = false,
|
||||
): WebpackPluginInstance[] {
|
||||
const minimizer = [
|
||||
new TerserPlugin({
|
||||
cache: true,
|
||||
parallel: getTerserParallel(),
|
||||
sourceMap: false,
|
||||
terserOptions: {
|
||||
parse: {
|
||||
// we want uglify-js to parse ecma 8 code. However, we don't want it
|
||||
|
@ -508,26 +521,20 @@ export function getMinimizer(useSimpleCssMinifier = false): Plugin[] {
|
|||
},
|
||||
}),
|
||||
];
|
||||
|
||||
if (useSimpleCssMinifier) {
|
||||
minimizer.push(
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessorPluginOptions: {
|
||||
preset: 'default',
|
||||
},
|
||||
}),
|
||||
);
|
||||
minimizer.push(new CssMinimizerPlugin());
|
||||
} else {
|
||||
minimizer.push(
|
||||
...[
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessorPluginOptions: {
|
||||
preset: CssNanoPreset,
|
||||
// Using the array syntax to add 2 minimizers
|
||||
// see https://github.com/webpack-contrib/css-minimizer-webpack-plugin#array
|
||||
new CssMinimizerPlugin({
|
||||
minimizerOptions: [
|
||||
// CssNano options
|
||||
{
|
||||
preset: require.resolve('@docusaurus/cssnano-preset'),
|
||||
},
|
||||
}),
|
||||
new OptimizeCSSAssetsPlugin({
|
||||
cssProcessor: CleanCss,
|
||||
cssProcessorOptions: {
|
||||
// CleanCss options
|
||||
{
|
||||
inline: false,
|
||||
level: {
|
||||
1: {
|
||||
|
@ -540,8 +547,12 @@ export function getMinimizer(useSimpleCssMinifier = false): Plugin[] {
|
|||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
],
|
||||
],
|
||||
minify: [
|
||||
CssMinimizerPlugin.cssnanoMinify,
|
||||
CssMinimizerPlugin.cleanCssMinify,
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"file-loader": "^6.2.0",
|
||||
"loader-utils": "^1.2.3",
|
||||
"lodash": "^4.17.20",
|
||||
"node-vibrant": "^3.1.5",
|
||||
"sharp": "^0.27.1"
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
const loaderUtils = require('loader-utils');
|
||||
const lqip = require('./lqip');
|
||||
|
||||
module.exports = function (contentBuffer) {
|
||||
|
@ -15,7 +14,7 @@ module.exports = function (contentBuffer) {
|
|||
const callback = this.async();
|
||||
const imgPath = this.resourcePath;
|
||||
|
||||
const config = loaderUtils.getOptions(this) || {};
|
||||
const config = this.getOptions() || {};
|
||||
config.base64 = 'base64' in config ? config.base64 : true;
|
||||
config.palette = 'palette' in config ? config.palette : false;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
/* Advanced Options */
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true, // @types/webpack and webpack/types.d.ts are not the same thing
|
||||
|
||||
/* Use tslib */
|
||||
"importHelpers": true,
|
||||
|
|
|
@ -398,7 +398,6 @@ type Props = {
|
|||
postBodyTags: string;
|
||||
routesPaths: string[];
|
||||
plugins: Plugin<any>[];
|
||||
stats: Stats.ToJsonOutput;
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -408,13 +407,11 @@ Example:
|
|||
module.exports = function (context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
async postBuild({siteConfig = {}, routesPaths = [], outDir, stats}) {
|
||||
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
|
||||
// Print out to console all the rendered routes.
|
||||
routesPaths.map((route) => {
|
||||
console.log(route);
|
||||
});
|
||||
// Print out to console all the webpack stats.
|
||||
console.log(stats);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,15 +1,27 @@
|
|||
|
||||
# Note: this file's config override the Netlify UI admin config
|
||||
# Note: this file's config overrides the Netlify UI admin config
|
||||
|
||||
# /!\ due to using a monorepo it can be a bit messy to configure Netlify
|
||||
# See also https://github.com/netlify/build/issues/2483
|
||||
|
||||
# default/production build
|
||||
[build]
|
||||
base = "/"
|
||||
command = "yarn workspace docusaurus-2-website netlify:build:production"
|
||||
command = "yarn --cwd .. build:packages && yarn build"
|
||||
publish = "website/build"
|
||||
|
||||
# we build deploy previews with a /build/ baseUrl on purpose
|
||||
# permits to test that baseUrl works fine (this often breaks!)
|
||||
[build.environment]
|
||||
NETLIFY_USE_YARN = "true"
|
||||
YARN_VERSION = "1.22.5"
|
||||
NODE_VERSION = "14"
|
||||
|
||||
[context.production]
|
||||
command = "yarn --cwd .. build:packages && yarn netlify:build:production"
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "yarn workspace docusaurus-2-website netlify:build:deployPreview"
|
||||
publish = "website/build"
|
||||
command = "yarn --cwd .. build:packages && yarn netlify:build:deployPreview"
|
||||
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
[plugins.inputs]
|
||||
paths = [
|
||||
"node_modules/.cache/webpack",
|
||||
]
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"@docusaurus/theme-live-codeblock": "2.0.0-alpha.74",
|
||||
"clsx": "^1.1.1",
|
||||
"color": "^3.1.3",
|
||||
"netlify-plugin-cache": "^1.0.3",
|
||||
"npm-to-yarn": "^1.0.0-2",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
|
|
Loading…
Add table
Reference in a new issue