mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-02 11:47:23 +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
|
# Ensure build with a cold cache does not increase too much
|
||||||
- name: Build (cold cache)
|
- name: Build (cold cache)
|
||||||
run: yarn workspace docusaurus-2-website build --locale en
|
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
|
# Ensure build with a warm cache does not increase too much
|
||||||
- name: Build (warm cache)
|
- name: Build (warm cache)
|
||||||
run: yarn workspace docusaurus-2-website build --locale en
|
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?
|
# 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
|
- name: Docusaurus Jest Tests
|
||||||
run: yarn test
|
run: yarn test
|
||||||
- name: Docusaurus Build
|
- name: Docusaurus Build
|
||||||
run: yarn build:v2
|
run: yarn build:v2 --locale en
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
|
|
@ -71,10 +71,11 @@
|
||||||
"@formatjs/intl-datetimeformat": "^3.2.12",
|
"@formatjs/intl-datetimeformat": "^3.2.12",
|
||||||
"@formatjs/intl-numberformat": "^6.2.2",
|
"@formatjs/intl-numberformat": "^6.2.2",
|
||||||
"@formatjs/intl-pluralrules": "^4.0.11",
|
"@formatjs/intl-pluralrules": "^4.0.11",
|
||||||
|
"@types/cssnano": "^4.0.0",
|
||||||
"@types/express": "^4.17.2",
|
"@types/express": "^4.17.2",
|
||||||
"@types/fs-extra": "^9.0.6",
|
"@types/fs-extra": "^9.0.6",
|
||||||
"@types/jest": "^26.0.20",
|
"@types/jest": "^26.0.20",
|
||||||
"@types/loader-utils": "^1.1.3",
|
"@types/loader-utils": "^2.0.2",
|
||||||
"@types/lodash": "^4.14.168",
|
"@types/lodash": "^4.14.168",
|
||||||
"@types/node": "^14.14.22",
|
"@types/node": "^14.14.22",
|
||||||
"@types/prismjs": "^1.16.2",
|
"@types/prismjs": "^1.16.2",
|
||||||
|
@ -87,9 +88,7 @@
|
||||||
"@types/semver": "^7.1.0",
|
"@types/semver": "^7.1.0",
|
||||||
"@types/shelljs": "^0.8.6",
|
"@types/shelljs": "^0.8.6",
|
||||||
"@types/wait-on": "^5.2.0",
|
"@types/wait-on": "^5.2.0",
|
||||||
"@types/webpack": "^4.41.0",
|
"@types/webpack-dev-server": "^3.11.1",
|
||||||
"@types/webpack-dev-server": "^3.9.0",
|
|
||||||
"@types/webpack-merge": "^4.1.5",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||||
"@typescript-eslint/parser": "^4.18.0",
|
"@typescript-eslint/parser": "^4.18.0",
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
|
|
|
@ -9,14 +9,17 @@ const advancedBasePreset = require('cssnano-preset-advanced');
|
||||||
const postCssSortMediaQueries = require('postcss-sort-media-queries');
|
const postCssSortMediaQueries = require('postcss-sort-media-queries');
|
||||||
const postCssRemoveOverriddenCustomProperties = require('./src/remove-overridden-custom-properties');
|
const postCssRemoveOverriddenCustomProperties = require('./src/remove-overridden-custom-properties');
|
||||||
|
|
||||||
const preset = advancedBasePreset({
|
module.exports = function docusaurusCssnanoPreset(opts) {
|
||||||
autoprefixer: {add: false},
|
const advancedPreset = advancedBasePreset({
|
||||||
discardComments: {removeAll: true},
|
autoprefixer: {add: false},
|
||||||
});
|
discardComments: {removeAll: true},
|
||||||
|
...opts,
|
||||||
|
});
|
||||||
|
|
||||||
preset.plugins.unshift(
|
advancedPreset.plugins.unshift(
|
||||||
[postCssSortMediaQueries],
|
[postCssSortMediaQueries],
|
||||||
[postCssRemoveOverriddenCustomProperties],
|
[postCssRemoveOverriddenCustomProperties],
|
||||||
);
|
);
|
||||||
|
|
||||||
module.exports = preset;
|
return advancedPreset;
|
||||||
|
};
|
||||||
|
|
|
@ -13,9 +13,9 @@
|
||||||
"directory": "packages/docusaurus-cssnano-preset"
|
"directory": "packages/docusaurus-cssnano-preset"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssnano-preset-advanced": "^4.0.7",
|
"cssnano-preset-advanced": "^5.0.0",
|
||||||
"postcss": "^7.0.2",
|
"postcss": "^8.2.10",
|
||||||
"postcss-sort-media-queries": "^1.7.26"
|
"postcss-sort-media-queries": "^3.8.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"to-vfile": "^6.0.0"
|
"to-vfile": "^6.0.0"
|
||||||
|
|
|
@ -5,40 +5,38 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
const sameProperties =
|
||||||
This PostCSS plugin will remove duplicate/same custom properties (which are actually overridden ones) **only** from `:root` selector.
|
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).
|
overriddenProperties.map((p) => p.remove());
|
||||||
- If the same custom properties have at least one `!important` rule, then only those properties that do not have this rule will be removed.
|
},
|
||||||
*/
|
};
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = postcss.plugin(
|
module.exports.postcss = true;
|
||||||
'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());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
|
@ -16,10 +16,13 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-alpha.74",
|
"@docusaurus/core": "2.0.0-alpha.74",
|
||||||
"@docusaurus/preset-bootstrap": "2.0.0-alpha.74",
|
"@docusaurus/preset-bootstrap": "2.0.0-alpha.74",
|
||||||
"@mdx-js/react": "^1.5.8",
|
"@mdx-js/react": "^1.6.21",
|
||||||
"classnames": "^2.2.6",
|
"@svgr/webpack": "^5.5.0",
|
||||||
|
"clsx": "^1.1.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1"
|
"react-dom": "^17.0.1",
|
||||||
|
"url-loader": "^4.1.1"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classnames from 'classnames';
|
import clsx from 'clsx';
|
||||||
import Layout from '@theme/Layout';
|
import Layout from '@theme/Layout';
|
||||||
import Link from '@docusaurus/Link';
|
import Link from '@docusaurus/Link';
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
||||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
|
@ -43,7 +42,7 @@ const features = [
|
||||||
function Feature({imageUrl, title, description}) {
|
function Feature({imageUrl, title, description}) {
|
||||||
const imgUrl = useBaseUrl(imageUrl);
|
const imgUrl = useBaseUrl(imageUrl);
|
||||||
return (
|
return (
|
||||||
<div className={classnames('col col--4', styles.feature)}>
|
<div className={clsx('col col--4', styles.feature)}>
|
||||||
{imgUrl && (
|
{imgUrl && (
|
||||||
<div className="text--center">
|
<div className="text--center">
|
||||||
<img className={styles.featureImage} src={imgUrl} alt={title} />
|
<img className={styles.featureImage} src={imgUrl} alt={title} />
|
||||||
|
|
|
@ -17,9 +17,12 @@
|
||||||
"@docusaurus/core": "2.0.0-alpha.74",
|
"@docusaurus/core": "2.0.0-alpha.74",
|
||||||
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
||||||
"@mdx-js/react": "^1.6.21",
|
"@mdx-js/react": "^1.6.21",
|
||||||
|
"@svgr/webpack": "^5.5.0",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1"
|
"react-dom": "^17.0.1",
|
||||||
|
"url-loader": "^4.1.1"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
|
|
|
@ -21,9 +21,12 @@
|
||||||
"@docusaurus/core": "2.0.0-alpha.74",
|
"@docusaurus/core": "2.0.0-alpha.74",
|
||||||
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
"@docusaurus/preset-classic": "2.0.0-alpha.74",
|
||||||
"@mdx-js/react": "^1.6.21",
|
"@mdx-js/react": "^1.6.21",
|
||||||
|
"@svgr/webpack": "^5.5.0",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1"
|
"react-dom": "^17.0.1",
|
||||||
|
"url-loader": "^4.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/eslint-parser": "^7.13.10",
|
"@babel/eslint-parser": "^7.13.10",
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"fs-extra": "^9.1.0",
|
"fs-extra": "^9.1.0",
|
||||||
"github-slugger": "^1.3.0",
|
"github-slugger": "^1.3.0",
|
||||||
"loader-utils": "^2.0.0",
|
"gray-matter": "^4.0.2",
|
||||||
"mdast-util-to-string": "^2.0.0",
|
"mdast-util-to-string": "^2.0.0",
|
||||||
"remark-emoji": "^2.1.0",
|
"remark-emoji": "^2.1.0",
|
||||||
"stringify-object": "^3.3.0",
|
"stringify-object": "^3.3.0",
|
||||||
"unist-util-visit": "^2.0.2",
|
"unist-util-visit": "^2.0.2",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"webpack": "^4.44.1"
|
"webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/types": "2.0.0-alpha.74",
|
"@docusaurus/types": "2.0.0-alpha.74",
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {getOptions} = require('loader-utils');
|
|
||||||
const {readFile} = require('fs-extra');
|
const {readFile} = require('fs-extra');
|
||||||
const mdx = require('@mdx-js/mdx');
|
const mdx = require('@mdx-js/mdx');
|
||||||
const emoji = require('remark-emoji');
|
const emoji = require('remark-emoji');
|
||||||
|
@ -27,7 +26,8 @@ const DEFAULT_OPTIONS = {
|
||||||
|
|
||||||
module.exports = async function docusaurusMdxLoader(fileString) {
|
module.exports = async function docusaurusMdxLoader(fileString) {
|
||||||
const callback = this.async();
|
const callback = this.async();
|
||||||
const reqOptions = getOptions(this) || {};
|
|
||||||
|
const reqOptions = this.getOptions() || {};
|
||||||
|
|
||||||
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
const {frontMatter, content: contentWithTitle} = parseFrontMatter(fileString);
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ const createJSX = (node, pathUrl) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
async function ensureImageFileExist(imagePath, sourceFilePath) {
|
async function ensureImageFileExist(imagePath, sourceFilePath) {
|
||||||
const imageExists = await fs.exists(imagePath);
|
const imageExists = await fs.pathExists(imagePath);
|
||||||
if (!imageExists) {
|
if (!imageExists) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Image ${toMessageRelativeFilePath(
|
`Image ${toMessageRelativeFilePath(
|
||||||
|
|
|
@ -20,7 +20,7 @@ const {
|
||||||
} = getFileLoaderUtils();
|
} = getFileLoaderUtils();
|
||||||
|
|
||||||
async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
|
async function ensureAssetFileExist(fileSystemAssetPath, sourceFilePath) {
|
||||||
const assetExists = await fs.exists(fileSystemAssetPath);
|
const assetExists = await fs.pathExists(fileSystemAssetPath);
|
||||||
if (!assetExists) {
|
if (!assetExists) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Asset ${toMessageRelativeFilePath(
|
`Asset ${toMessageRelativeFilePath(
|
||||||
|
@ -85,12 +85,12 @@ async function convertToAssetLinkIfNeeded({node, staticDir, filePath}) {
|
||||||
toAssetLinkNode(fileSystemAssetPath);
|
toAssetLinkNode(fileSystemAssetPath);
|
||||||
} else if (path.isAbsolute(assetPath)) {
|
} else if (path.isAbsolute(assetPath)) {
|
||||||
const fileSystemAssetPath = path.join(staticDir, assetPath);
|
const fileSystemAssetPath = path.join(staticDir, assetPath);
|
||||||
if (await fs.exists(fileSystemAssetPath)) {
|
if (await fs.pathExists(fileSystemAssetPath)) {
|
||||||
toAssetLinkNode(fileSystemAssetPath);
|
toAssetLinkNode(fileSystemAssetPath);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const fileSystemAssetPath = path.join(path.dirname(filePath), assetPath);
|
const fileSystemAssetPath = path.join(path.dirname(filePath), assetPath);
|
||||||
if (await fs.exists(fileSystemAssetPath)) {
|
if (await fs.pathExists(fileSystemAssetPath)) {
|
||||||
toAssetLinkNode(fileSystemAssetPath);
|
toAssetLinkNode(fileSystemAssetPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"fs-extra": "^9.1.0",
|
"fs-extra": "^9.1.0",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.2",
|
||||||
"loader-utils": "^1.2.3",
|
"loader-utils": "^2.0.0",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"reading-time": "^1.3.0",
|
"reading-time": "^1.3.0",
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"webpack": "^4.44.1"
|
"webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -44,7 +44,7 @@ import {
|
||||||
OptionValidationContext,
|
OptionValidationContext,
|
||||||
ValidationResult,
|
ValidationResult,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {Configuration, Loader} from 'webpack';
|
import {Configuration} from 'webpack';
|
||||||
import {
|
import {
|
||||||
generateBlogFeed,
|
generateBlogFeed,
|
||||||
generateBlogPosts,
|
generateBlogPosts,
|
||||||
|
@ -401,7 +401,7 @@ export default function pluginContentBlog(
|
||||||
configureWebpack(
|
configureWebpack(
|
||||||
_config: Configuration,
|
_config: Configuration,
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
|
{getJSLoader}: ConfigureWebpackUtils,
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
rehypePlugins,
|
rehypePlugins,
|
||||||
|
@ -441,8 +441,7 @@ export default function pluginContentBlog(
|
||||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||||
.map(addTrailingPathSeparator),
|
.map(addTrailingPathSeparator),
|
||||||
use: [
|
use: [
|
||||||
getCacheLoader(isServer),
|
getJSLoader({isServer}),
|
||||||
getBabelLoader(isServer),
|
|
||||||
{
|
{
|
||||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||||
options: {
|
options: {
|
||||||
|
@ -466,7 +465,7 @@ export default function pluginContentBlog(
|
||||||
loader: path.resolve(__dirname, './markdownLoader.js'),
|
loader: path.resolve(__dirname, './markdownLoader.js'),
|
||||||
options: markdownLoaderOptions,
|
options: markdownLoaderOptions,
|
||||||
},
|
},
|
||||||
].filter(Boolean) as Loader[],
|
].filter(Boolean),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,16 +5,21 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {loader} from 'webpack';
|
|
||||||
import {truncate, linkify} from './blogUtils';
|
import {truncate, linkify} from './blogUtils';
|
||||||
import {parseQuery, getOptions} from 'loader-utils';
|
import {parseQuery} from 'loader-utils';
|
||||||
import {BlogMarkdownLoaderOptions} from './types';
|
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 filePath = this.resourcePath;
|
||||||
const fileString = source as string;
|
const fileString = source as string;
|
||||||
const callback = this.async();
|
const callback = this.async();
|
||||||
const markdownLoaderOptions = getOptions(this) as BlogMarkdownLoaderOptions;
|
const markdownLoaderOptions = this.getOptions() as BlogMarkdownLoaderOptions;
|
||||||
|
|
||||||
// Linkify blog posts
|
// Linkify blog posts
|
||||||
let finalContent = linkify({
|
let finalContent = linkify({
|
||||||
|
@ -24,8 +29,8 @@ const markdownLoader: loader.Loader = function (source) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Truncate content if requested (e.g: file.md?truncated=true).
|
// Truncate content if requested (e.g: file.md?truncated=true).
|
||||||
const truncated: string | undefined = this.resourceQuery
|
const truncated: boolean | undefined = this.resourceQuery
|
||||||
? parseQuery(this.resourceQuery).truncated
|
? !!parseQuery(this.resourceQuery).truncated
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
if (truncated) {
|
if (truncated) {
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"utility-types": "^3.10.0",
|
"utility-types": "^3.10.0",
|
||||||
"webpack": "^4.44.1"
|
"webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -33,7 +33,6 @@ import {
|
||||||
} from '../types';
|
} from '../types';
|
||||||
import {toSidebarsProp} from '../props';
|
import {toSidebarsProp} from '../props';
|
||||||
|
|
||||||
// @ts-expect-error: TODO typedefs missing?
|
|
||||||
import {validate} from 'webpack';
|
import {validate} from 'webpack';
|
||||||
import {DefaultSidebarItemsGenerator} from '../sidebarItemsGenerator';
|
import {DefaultSidebarItemsGenerator} from '../sidebarItemsGenerator';
|
||||||
|
|
||||||
|
@ -253,7 +252,7 @@ describe('simple website', () => {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('content', async () => {
|
test('content', async () => {
|
||||||
|
|
|
@ -331,7 +331,7 @@ export default function pluginContentDocs(
|
||||||
},
|
},
|
||||||
|
|
||||||
configureWebpack(_config, isServer, utils) {
|
configureWebpack(_config, isServer, utils) {
|
||||||
const {getBabelLoader, getCacheLoader} = utils;
|
const {getJSLoader} = utils;
|
||||||
const {
|
const {
|
||||||
rehypePlugins,
|
rehypePlugins,
|
||||||
remarkPlugins,
|
remarkPlugins,
|
||||||
|
@ -361,8 +361,7 @@ export default function pluginContentDocs(
|
||||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||||
.map(addTrailingPathSeparator),
|
.map(addTrailingPathSeparator),
|
||||||
use: compact([
|
use: compact([
|
||||||
getCacheLoader(isServer),
|
getJSLoader({isServer}),
|
||||||
getBabelLoader(isServer),
|
|
||||||
{
|
{
|
||||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||||
options: {
|
options: {
|
||||||
|
@ -387,16 +386,13 @@ export default function pluginContentDocs(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suppress warnings about non-existing of versions file.
|
|
||||||
const stats = {
|
|
||||||
warningsFilter: [VERSIONS_JSON_FILE],
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stats,
|
ignoreWarnings: [
|
||||||
devServer: {
|
// Suppress warnings about non-existing of versions file.
|
||||||
stats,
|
(e) =>
|
||||||
},
|
e.message.includes("Can't resolve") &&
|
||||||
|
e.message.includes(VERSIONS_JSON_FILE),
|
||||||
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'~docs': pluginDataDirRoot,
|
'~docs': pluginDataDirRoot,
|
||||||
|
|
|
@ -5,15 +5,19 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {getOptions} from 'loader-utils';
|
|
||||||
import {loader} from 'webpack';
|
|
||||||
import {linkify} from './linkify';
|
import {linkify} from './linkify';
|
||||||
import {DocsMarkdownOption} from '../types';
|
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 fileString = source as string;
|
||||||
const callback = this.async();
|
const callback = this.async();
|
||||||
const options = getOptions(this) as DocsMarkdownOption;
|
const options = this.getOptions() as DocsMarkdownOption;
|
||||||
return (
|
return (
|
||||||
callback && callback(null, linkify(fileString, this.resourcePath, options))
|
callback && callback(null, linkify(fileString, this.resourcePath, options))
|
||||||
);
|
);
|
||||||
|
|
|
@ -24,13 +24,12 @@
|
||||||
"@docusaurus/utils": "2.0.0-alpha.74",
|
"@docusaurus/utils": "2.0.0-alpha.74",
|
||||||
"@docusaurus/utils-validation": "2.0.0-alpha.74",
|
"@docusaurus/utils-validation": "2.0.0-alpha.74",
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.2",
|
||||||
"loader-utils": "^1.2.3",
|
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"minimatch": "^3.0.4",
|
"minimatch": "^3.0.4",
|
||||||
"remark-admonitions": "^1.2.1",
|
"remark-admonitions": "^1.2.1",
|
||||||
"slash": "^3.0.0",
|
"slash": "^3.0.0",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"webpack": "^4.44.1"
|
"webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -26,7 +26,7 @@ import {
|
||||||
ValidationResult,
|
ValidationResult,
|
||||||
ConfigureWebpackUtils,
|
ConfigureWebpackUtils,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import {Configuration, Loader} from 'webpack';
|
import {Configuration} from 'webpack';
|
||||||
import admonitions from 'remark-admonitions';
|
import admonitions from 'remark-admonitions';
|
||||||
import {PluginOptionSchema} from './pluginOptionSchema';
|
import {PluginOptionSchema} from './pluginOptionSchema';
|
||||||
import {
|
import {
|
||||||
|
@ -192,7 +192,7 @@ export default function pluginContentPages(
|
||||||
configureWebpack(
|
configureWebpack(
|
||||||
_config: Configuration,
|
_config: Configuration,
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
|
{getJSLoader}: ConfigureWebpackUtils,
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
rehypePlugins,
|
rehypePlugins,
|
||||||
|
@ -214,8 +214,7 @@ export default function pluginContentPages(
|
||||||
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
||||||
.map(addTrailingPathSeparator),
|
.map(addTrailingPathSeparator),
|
||||||
use: [
|
use: [
|
||||||
getCacheLoader(isServer),
|
getJSLoader({isServer}),
|
||||||
getBabelLoader(isServer),
|
|
||||||
{
|
{
|
||||||
loader: require.resolve('@docusaurus/mdx-loader'),
|
loader: require.resolve('@docusaurus/mdx-loader'),
|
||||||
options: {
|
options: {
|
||||||
|
@ -248,7 +247,7 @@ export default function pluginContentPages(
|
||||||
// contentPath,
|
// contentPath,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
].filter(Boolean) as Loader[],
|
].filter(Boolean),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,13 +5,16 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {loader} from 'webpack';
|
// TODO temporary until Webpack5 export this type
|
||||||
// import {getOptions} from 'loader-utils';
|
// 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 callback = this.async();
|
||||||
|
|
||||||
// const options = getOptions(this);
|
// const options = this.getOptions();
|
||||||
|
|
||||||
// TODO provide additinal md processing here? like interlinking pages?
|
// TODO provide additinal md processing here? like interlinking pages?
|
||||||
// fileString = linkify(fileString)
|
// fileString = linkify(fileString)
|
||||||
|
|
|
@ -24,11 +24,11 @@
|
||||||
"@docusaurus/lqip-loader": "2.0.0-alpha.74",
|
"@docusaurus/lqip-loader": "2.0.0-alpha.74",
|
||||||
"@docusaurus/types": "2.0.0-alpha.74",
|
"@docusaurus/types": "2.0.0-alpha.74",
|
||||||
"@endiliey/react-ideal-image": "^0.0.11",
|
"@endiliey/react-ideal-image": "^0.0.11",
|
||||||
"@endiliey/responsive-loader": "^1.3.2",
|
|
||||||
"react-waypoint": "^9.0.2",
|
"react-waypoint": "^9.0.2",
|
||||||
|
"@docusaurus/responsive-loader": "1.4.0",
|
||||||
"sharp": "^0.27.1",
|
"sharp": "^0.27.1",
|
||||||
"tslib": "^2.1.0",
|
"tslib": "^2.1.0",
|
||||||
"webpack": "^4.44.1"
|
"webpack": "^5.28.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^16.8.4 || ^17.0.0",
|
"react": "^16.8.4 || ^17.0.0",
|
||||||
|
|
|
@ -35,12 +35,11 @@ export default function (
|
||||||
use: [
|
use: [
|
||||||
require.resolve('@docusaurus/lqip-loader'),
|
require.resolve('@docusaurus/lqip-loader'),
|
||||||
{
|
{
|
||||||
loader: require.resolve('@endiliey/responsive-loader'),
|
loader: require.resolve('@docusaurus/responsive-loader'),
|
||||||
options: {
|
options: {
|
||||||
emitFile: !isServer, // don't emit for server-side rendering
|
emitFile: !isServer, // don't emit for server-side rendering
|
||||||
disable: !isProd,
|
disable: !isProd,
|
||||||
// eslint-disable-next-line
|
adapter: require('@docusaurus/responsive-loader/sharp'),
|
||||||
adapter: require('@endiliey/responsive-loader/sharp'),
|
|
||||||
name: isProd
|
name: isProd
|
||||||
? 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]'
|
? 'assets/ideal-img/[name].[hash:hex:7].[width].[ext]'
|
||||||
: 'assets/ideal-img/[name].[width].[ext]',
|
: 'assets/ideal-img/[name].[width].[ext]',
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"core-js": "^2.6.5",
|
"core-js": "^2.6.5",
|
||||||
"terser-webpack-plugin": "^4.1.0",
|
"terser-webpack-plugin": "^5.1.1",
|
||||||
"webpack": "^4.44.1",
|
"webpack": "^5.28.0",
|
||||||
"webpack-merge": "^4.2.2",
|
"webpack-merge": "^5.7.3",
|
||||||
"workbox-build": "^6.1.1",
|
"workbox-build": "^6.1.1",
|
||||||
"workbox-precaching": "^6.1.1",
|
"workbox-precaching": "^6.1.1",
|
||||||
"workbox-window": "^6.1.1"
|
"workbox-window": "^6.1.1"
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* 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 {compile} = require('@docusaurus/core/lib/webpack/utils');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
@ -127,7 +128,7 @@ function plugin(context, options) {
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.EnvironmentPlugin({
|
new webpack.EnvironmentPlugin({
|
||||||
PWA_SW_CUSTOM: swCustom,
|
PWA_SW_CUSTOM: swCustom || '', // fallback value required with Webpack 5
|
||||||
}),
|
}),
|
||||||
new LogPlugin({
|
new LogPlugin({
|
||||||
name: 'Service Worker',
|
name: 'Service Worker',
|
||||||
|
|
|
@ -41,12 +41,12 @@
|
||||||
"infima": "0.2.0-alpha.23",
|
"infima": "0.2.0-alpha.23",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"parse-numeric-range": "^1.2.0",
|
"parse-numeric-range": "^1.2.0",
|
||||||
"postcss": "^7.0.2",
|
"postcss": "^8.2.10",
|
||||||
"prism-react-renderer": "^1.1.1",
|
"prism-react-renderer": "^1.1.1",
|
||||||
"prismjs": "^1.23.0",
|
"prismjs": "^1.23.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"rtlcss": "^2.6.2"
|
"rtlcss": "^3.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "2.0.0-alpha.74"
|
"@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 {getTranslationFiles, translateThemeConfig} from './translations';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import Module from 'module';
|
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 rtlcss from 'rtlcss';
|
||||||
import {readDefaultCodeTranslationMessages} from '@docusaurus/utils';
|
import {readDefaultCodeTranslationMessages} from '@docusaurus/utils';
|
||||||
|
|
||||||
|
@ -139,14 +139,11 @@ export default function docusaurusThemeClassic(
|
||||||
.map((lang) => `prism-${lang}`)
|
.map((lang) => `prism-${lang}`)
|
||||||
.join('|');
|
.join('|');
|
||||||
|
|
||||||
// See https://github.com/facebook/docusaurus/pull/3382
|
|
||||||
const useDocsWarningFilter = (warning: string) =>
|
|
||||||
warning.includes("Can't resolve '@theme-init/hooks/useDocs");
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
stats: {
|
ignoreWarnings: [
|
||||||
warningsFilter: useDocsWarningFilter,
|
// See https://github.com/facebook/docusaurus/pull/3382
|
||||||
},
|
(e) => e.message.includes("Can't resolve '@theme-init/hooks/useDocs"),
|
||||||
|
],
|
||||||
plugins: [
|
plugins: [
|
||||||
new ContextReplacementPlugin(
|
new ContextReplacementPlugin(
|
||||||
/prismjs[\\/]components$/,
|
/prismjs[\\/]components$/,
|
||||||
|
@ -156,29 +153,21 @@ export default function docusaurusThemeClassic(
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
configurePostCss(postCssOptions) {
|
configurePostCss(postCssOptions: {plugins: AcceptedPlugin[]}) {
|
||||||
if (direction === 'rtl') {
|
if (direction === 'rtl') {
|
||||||
postCssOptions.plugins.push(
|
const resolvedInfimaFile = require.resolve(getInfimaCSSFile(direction));
|
||||||
postcss.plugin('RtlCssPlugin', () => {
|
const plugin: PostCssPlugin = {
|
||||||
const resolvedInfimaFile = require.resolve(
|
postcssPlugin: 'RtlCssPlugin',
|
||||||
getInfimaCSSFile(direction),
|
prepare: (result: Result) => {
|
||||||
);
|
const file = result.root?.source?.input?.file;
|
||||||
function isInfimaCSSFile(file?: string) {
|
// Skip Infima as we are using the its RTL version.
|
||||||
return file === resolvedInfimaFile;
|
if (file === resolvedInfimaFile) {
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
return rtlcss(result.root);
|
||||||
return function (root: PostCssRoot) {
|
},
|
||||||
const file = root?.source?.input.file;
|
};
|
||||||
|
postCssOptions.plugins.push(plugin);
|
||||||
// Skip Infima as we are using the its RTL version.
|
|
||||||
if (isInfimaCSSFile(file)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtlcss.process(root);
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return postCssOptions;
|
return postCssOptions;
|
||||||
|
|
|
@ -15,6 +15,7 @@ export type NavbarItem = {
|
||||||
type?: string | undefined;
|
type?: string | undefined;
|
||||||
items?: NavbarItem[];
|
items?: NavbarItem[];
|
||||||
label?: string;
|
label?: string;
|
||||||
|
position?: 'left' | 'right';
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NavbarLogo = {
|
export type NavbarLogo = {
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/webpack": "^4.41.0",
|
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
"joi": "^17.4.0",
|
"joi": "^17.4.0",
|
||||||
"querystring": "0.2.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 doesn't understand types dependencies in d.ts
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// 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 {Command} from 'commander';
|
||||||
import type {ParsedUrlQueryInput} from 'querystring';
|
import type {ParsedUrlQueryInput} from 'querystring';
|
||||||
import type {MergeStrategy} from 'webpack-merge';
|
|
||||||
import type Joi from 'joi';
|
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 ReportingSeverity = 'ignore' | 'log' | 'warn' | 'error' | 'throw';
|
||||||
|
|
||||||
export type ThemeConfig = {
|
export type ThemeConfig = {
|
||||||
|
@ -186,18 +190,12 @@ export interface InjectedHtmlTags {
|
||||||
export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
|
export type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
|
||||||
|
|
||||||
export interface Props extends LoadContext, InjectedHtmlTags {
|
export interface Props extends LoadContext, InjectedHtmlTags {
|
||||||
|
siteMetadata: DocusaurusSiteMetadata;
|
||||||
routes: RouteConfig[];
|
routes: RouteConfig[];
|
||||||
routesPaths: string[];
|
routesPaths: string[];
|
||||||
plugins: Plugin<unknown>[];
|
plugins: Plugin<unknown>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as `Props` but also has webpack stats appended.
|
|
||||||
*/
|
|
||||||
export interface PropsPostBuild extends Props {
|
|
||||||
stats: Stats.ToJsonOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface PluginContentLoadedActions {
|
export interface PluginContentLoadedActions {
|
||||||
addRoute(config: RouteConfig): void;
|
addRoute(config: RouteConfig): void;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -228,7 +226,7 @@ export interface Plugin<Content> {
|
||||||
actions: PluginContentLoadedActions;
|
actions: PluginContentLoadedActions;
|
||||||
}): void;
|
}): void;
|
||||||
routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60)
|
routesLoaded?(routes: RouteConfig[]): void; // TODO remove soon, deprecated (alpha-60)
|
||||||
postBuild?(props: PropsPostBuild): void;
|
postBuild?(props: Props): void;
|
||||||
postStart?(props: Props): void;
|
postStart?(props: Props): void;
|
||||||
configureWebpack?(
|
configureWebpack?(
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
|
@ -335,15 +333,23 @@ export interface ConfigureWebpackUtils {
|
||||||
cssOptions: {
|
cssOptions: {
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
},
|
},
|
||||||
) => Loader[];
|
) => RuleSetRule[];
|
||||||
|
getJSLoader: (options: {
|
||||||
|
isServer: boolean;
|
||||||
|
babelOptions?: Record<string, unknown>;
|
||||||
|
}) => RuleSetRule;
|
||||||
|
|
||||||
|
// TODO deprecated: remove before end of 2021?
|
||||||
getCacheLoader: (
|
getCacheLoader: (
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
cacheOptions?: Record<string, unknown>,
|
cacheOptions?: Record<string, unknown>,
|
||||||
) => Loader | null;
|
) => RuleSetRule | null;
|
||||||
|
|
||||||
|
// TODO deprecated: remove before end of 2021?
|
||||||
getBabelLoader: (
|
getBabelLoader: (
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
babelOptions?: Record<string, unknown>,
|
options?: Record<string, unknown>,
|
||||||
) => Loader;
|
) => RuleSetRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HtmlTagObject {
|
interface HtmlTagObject {
|
||||||
|
|
|
@ -39,8 +39,6 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "^7.12.16",
|
"@babel/core": "^7.12.16",
|
||||||
"@babel/generator": "^7.12.15",
|
"@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-syntax-dynamic-import": "^7.8.3",
|
||||||
"@babel/plugin-transform-runtime": "^7.12.15",
|
"@babel/plugin-transform-runtime": "^7.12.15",
|
||||||
"@babel/preset-env": "^7.12.16",
|
"@babel/preset-env": "^7.12.16",
|
||||||
|
@ -60,14 +58,15 @@
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"babel-plugin-dynamic-import-node": "2.3.0",
|
"babel-plugin-dynamic-import-node": "2.3.0",
|
||||||
"boxen": "^5.0.0",
|
"boxen": "^5.0.0",
|
||||||
"cache-loader": "^4.1.0",
|
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"clean-css": "^5.1.1",
|
"clean-css": "^5.1.1",
|
||||||
"commander": "^5.1.0",
|
"commander": "^5.1.0",
|
||||||
"copy-webpack-plugin": "^6.4.1",
|
"copy-webpack-plugin": "^8.1.0",
|
||||||
"core-js": "^3.9.1",
|
"core-js": "^3.9.1",
|
||||||
"css-loader": "^5.1.1",
|
"css-loader": "^5.1.1",
|
||||||
|
"css-minimizer-webpack-plugin": "^2.0.0",
|
||||||
|
"cssnano": "^5.0.1",
|
||||||
"del": "^6.0.0",
|
"del": "^6.0.0",
|
||||||
"detect-port": "^1.3.0",
|
"detect-port": "^1.3.0",
|
||||||
"eta": "^1.12.1",
|
"eta": "^1.12.1",
|
||||||
|
@ -78,24 +77,22 @@
|
||||||
"globby": "^11.0.2",
|
"globby": "^11.0.2",
|
||||||
"html-minifier-terser": "^5.1.1",
|
"html-minifier-terser": "^5.1.1",
|
||||||
"html-tags": "^3.1.0",
|
"html-tags": "^3.1.0",
|
||||||
"html-webpack-plugin": "^4.5.0",
|
"html-webpack-plugin": "^5.2.0",
|
||||||
"import-fresh": "^3.3.0",
|
"import-fresh": "^3.3.0",
|
||||||
"is-root": "^2.1.0",
|
"is-root": "^2.1.0",
|
||||||
"leven": "^3.1.0",
|
"leven": "^3.1.0",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"mini-css-extract-plugin": "^0.8.0",
|
"mini-css-extract-plugin": "^1.4.0",
|
||||||
"module-alias": "^2.2.2",
|
"module-alias": "^2.2.2",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"null-loader": "^4.0.0",
|
"postcss": "^8.2.10",
|
||||||
"optimize-css-assets-webpack-plugin": "^5.0.4",
|
"postcss-loader": "^5.2.0",
|
||||||
"pnp-webpack-plugin": "^1.6.4",
|
|
||||||
"postcss": "^8.2.7",
|
|
||||||
"postcss-loader": "^4.1.0",
|
|
||||||
"prompts": "^2.4.0",
|
"prompts": "^2.4.0",
|
||||||
"react-dev-utils": "^11.0.1",
|
"react-dev-utils": "^11.0.1",
|
||||||
|
"react-error-overlay": "^6.0.9",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-loadable": "^5.5.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": "^5.2.0",
|
||||||
"react-router-config": "^5.1.1",
|
"react-router-config": "^5.1.1",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
|
@ -105,15 +102,16 @@
|
||||||
"serve-handler": "^6.1.3",
|
"serve-handler": "^6.1.3",
|
||||||
"shelljs": "^0.8.4",
|
"shelljs": "^0.8.4",
|
||||||
"std-env": "^2.2.1",
|
"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",
|
"tslib": "^2.1.0",
|
||||||
"update-notifier": "^5.1.0",
|
"update-notifier": "^5.1.0",
|
||||||
"url-loader": "^4.1.1",
|
"url-loader": "^4.1.1",
|
||||||
"wait-on": "^5.2.1",
|
"wait-on": "^5.2.1",
|
||||||
"webpack": "^4.44.1",
|
"webpack": "^5.28.0",
|
||||||
"webpack-bundle-analyzer": "^4.4.0",
|
"webpack-bundle-analyzer": "^4.4.0",
|
||||||
"webpack-dev-server": "^3.11.2",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"webpack-merge": "^4.2.2",
|
"webpack-merge": "^5.7.3",
|
||||||
"webpackbar": "^5.0.0-3"
|
"webpackbar": "^5.0.0-3"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
|
@ -64,12 +64,6 @@ function getTransformOptions(isServer: boolean): TransformOptions {
|
||||||
isServer
|
isServer
|
||||||
? require.resolve('babel-plugin-dynamic-import-node')
|
? require.resolve('babel-plugin-dynamic-import-node')
|
||||||
: require.resolve('@babel/plugin-syntax-dynamic-import'),
|
: 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 {StaticRouter} from 'react-router-dom';
|
||||||
import ReactDOMServer from 'react-dom/server';
|
import ReactDOMServer from 'react-dom/server';
|
||||||
import {Helmet} from 'react-helmet';
|
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 Loadable from 'react-loadable';
|
||||||
|
|
||||||
import {minify} from 'html-minifier-terser';
|
import {minify} from 'html-minifier-terser';
|
||||||
|
|
|
@ -9,8 +9,8 @@ import chalk from 'chalk';
|
||||||
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import ReactLoadableSSRAddon from 'react-loadable-ssr-addon';
|
import ReactLoadableSSRAddon from 'react-loadable-ssr-addon-v5-slorber';
|
||||||
import {Configuration, Plugin} from 'webpack';
|
import {Configuration} from 'webpack';
|
||||||
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
|
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
|
||||||
import merge from 'webpack-merge';
|
import merge from 'webpack-merge';
|
||||||
import {STATIC_DIR_NAME} from '../constants';
|
import {STATIC_DIR_NAME} from '../constants';
|
||||||
|
@ -21,9 +21,9 @@ import {BuildCLIOptions, Props} from '@docusaurus/types';
|
||||||
import createClientConfig from '../webpack/client';
|
import createClientConfig from '../webpack/client';
|
||||||
import createServerConfig from '../webpack/server';
|
import createServerConfig from '../webpack/server';
|
||||||
import {
|
import {
|
||||||
compile,
|
|
||||||
applyConfigureWebpack,
|
|
||||||
applyConfigurePostCss,
|
applyConfigurePostCss,
|
||||||
|
applyConfigureWebpack,
|
||||||
|
compile,
|
||||||
} from '../webpack/utils';
|
} from '../webpack/utils';
|
||||||
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
|
import CleanWebpackPlugin from '../webpack/plugins/CleanWebpackPlugin';
|
||||||
import {loadI18n} from '../server/i18n';
|
import {loadI18n} from '../server/i18n';
|
||||||
|
@ -44,15 +44,14 @@ export default async function build(
|
||||||
isLastLocale: boolean;
|
isLastLocale: boolean;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const result = await buildLocale({
|
// console.log(chalk.green(`Site successfully built in locale=${locale}`));
|
||||||
|
return await buildLocale({
|
||||||
siteDir,
|
siteDir,
|
||||||
locale,
|
locale,
|
||||||
cliOptions,
|
cliOptions,
|
||||||
forceTerminate,
|
forceTerminate,
|
||||||
isLastLocale,
|
isLastLocale,
|
||||||
});
|
});
|
||||||
// console.log(chalk.green(`Site successfully built in locale=${locale}`));
|
|
||||||
return result;
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`error building locale=${locale}`);
|
console.error(`error building locale=${locale}`);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -146,7 +145,7 @@ async function buildLocale({
|
||||||
new ReactLoadableSSRAddon({
|
new ReactLoadableSSRAddon({
|
||||||
filename: clientManifestPath,
|
filename: clientManifestPath,
|
||||||
}),
|
}),
|
||||||
].filter(Boolean) as Plugin[],
|
].filter(Boolean),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -160,7 +159,7 @@ async function buildLocale({
|
||||||
});
|
});
|
||||||
|
|
||||||
const staticDir = path.resolve(siteDir, STATIC_DIR_NAME);
|
const staticDir = path.resolve(siteDir, STATIC_DIR_NAME);
|
||||||
if (fs.existsSync(staticDir)) {
|
if (await fs.pathExists(staticDir)) {
|
||||||
serverConfig = merge(serverConfig, {
|
serverConfig = merge(serverConfig, {
|
||||||
plugins: [
|
plugins: [
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
|
@ -200,12 +199,12 @@ async function buildLocale({
|
||||||
|
|
||||||
// Make sure generated client-manifest is cleaned first so we don't reuse
|
// Make sure generated client-manifest is cleaned first so we don't reuse
|
||||||
// the one from previous builds.
|
// the one from previous builds.
|
||||||
if (fs.existsSync(clientManifestPath)) {
|
if (await fs.pathExists(clientManifestPath)) {
|
||||||
fs.unlinkSync(clientManifestPath);
|
await fs.unlink(clientManifestPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run webpack to build JS bundle (client) and static html files (server).
|
// 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.
|
// Remove server.bundle.js because it is not needed.
|
||||||
if (
|
if (
|
||||||
|
@ -214,11 +213,9 @@ async function buildLocale({
|
||||||
typeof serverConfig.output.filename === 'string'
|
typeof serverConfig.output.filename === 'string'
|
||||||
) {
|
) {
|
||||||
const serverBundle = path.join(outDir, serverConfig.output.filename);
|
const serverBundle = path.join(outDir, serverConfig.output.filename);
|
||||||
fs.pathExists(serverBundle).then((exist) => {
|
if (await fs.pathExists(serverBundle)) {
|
||||||
if (exist) {
|
await fs.unlink(serverBundle);
|
||||||
fs.unlink(serverBundle);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin Lifecycle - postBuild.
|
// Plugin Lifecycle - postBuild.
|
||||||
|
@ -227,7 +224,7 @@ async function buildLocale({
|
||||||
if (!plugin.postBuild) {
|
if (!plugin.postBuild) {
|
||||||
return;
|
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 openBrowser from 'react-dev-utils/openBrowser';
|
||||||
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
|
import {prepareUrls} from 'react-dev-utils/WebpackDevServerUtils';
|
||||||
import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';
|
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 webpack from 'webpack';
|
||||||
import WebpackDevServer from 'webpack-dev-server';
|
import WebpackDevServer from 'webpack-dev-server';
|
||||||
import merge from 'webpack-merge';
|
import merge from 'webpack-merge';
|
||||||
|
@ -191,16 +192,12 @@ export default async function start(
|
||||||
baseUrl,
|
baseUrl,
|
||||||
express.static(path.resolve(siteDir, STATIC_DIR_NAME)),
|
express.static(path.resolve(siteDir, STATIC_DIR_NAME)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// This lets us fetch source contents from webpack for the error overlay.
|
// This lets us fetch source contents from webpack for the error overlay.
|
||||||
app.use(evalSourceMapMiddleware(server));
|
app.use(evalSourceMapMiddleware(server));
|
||||||
// This lets us open files from the runtime error overlay.
|
// This lets us open files from the runtime error overlay.
|
||||||
app.use(errorOverlayMiddleware());
|
app.use(errorOverlayMiddleware());
|
||||||
|
|
||||||
// TODO: add plugins beforeDevServer and afterDevServer hook
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...config.devServer,
|
|
||||||
};
|
};
|
||||||
const compiler = webpack(config);
|
const compiler = webpack(config);
|
||||||
if (process.env.E2E_TEST) {
|
if (process.env.E2E_TEST) {
|
||||||
|
@ -213,6 +210,7 @@ export default async function start(
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const devServer = new WebpackDevServer(compiler, devServerConfig);
|
const devServer = new WebpackDevServer(compiler, devServerConfig);
|
||||||
devServer.listen(port, host, (err) => {
|
devServer.listen(port, host, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -9,6 +9,10 @@ export const NODE_MAJOR_VERSION = parseInt(
|
||||||
process.versions.node.split('.')[0],
|
process.versions.node.split('.')[0],
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
|
export const NODE_MINOR_VERSION = parseInt(
|
||||||
|
process.versions.node.split('.')[1],
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
|
||||||
// Can be overridden with cli option --out-dir
|
// Can be overridden with cli option --out-dir
|
||||||
export const DEFAULT_BUILD_DIR_NAME = 'build';
|
export const DEFAULT_BUILD_DIR_NAME = 'build';
|
||||||
|
|
|
@ -325,6 +325,7 @@ ${Object.keys(registry)
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
siteConfig,
|
siteConfig,
|
||||||
siteConfigPath,
|
siteConfigPath,
|
||||||
|
siteMetadata,
|
||||||
siteDir,
|
siteDir,
|
||||||
outDir,
|
outDir,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
|
|
|
@ -84,6 +84,12 @@ describe('base webpack config', () => {
|
||||||
baseUrl: '',
|
baseUrl: '',
|
||||||
generatedFilesDir: '',
|
generatedFilesDir: '',
|
||||||
routesPaths: '',
|
routesPaths: '',
|
||||||
|
i18n: {
|
||||||
|
currentLocale: 'en',
|
||||||
|
},
|
||||||
|
siteMetadata: {
|
||||||
|
docusaurusVersion: '2.0.0-alpha.70',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('webpack dev config', () => {
|
||||||
const props = await loadSetup('simple');
|
const props = await loadSetup('simple');
|
||||||
const config = createClientConfig(props);
|
const config = createClientConfig(props);
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('custom', async () => {
|
test('custom', async () => {
|
||||||
|
@ -24,6 +24,6 @@ describe('webpack dev config', () => {
|
||||||
const props = await loadSetup('custom');
|
const props = await loadSetup('custom');
|
||||||
const config = createClientConfig(props);
|
const config = createClientConfig(props);
|
||||||
const errors = validate(config);
|
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 props = await loadSetup('simple');
|
||||||
const config = createServerConfig({props});
|
const config = createServerConfig({props});
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('custom', async () => {
|
test('custom', async () => {
|
||||||
|
@ -24,6 +24,6 @@ describe('webpack production config', () => {
|
||||||
const props = await loadSetup('custom');
|
const props = await loadSetup('custom');
|
||||||
const config = createServerConfig({props});
|
const config = createServerConfig({props});
|
||||||
const errors = validate(config);
|
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.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {validate, Configuration} from 'webpack';
|
||||||
// @ts-expect-error: seems it's not in the typedefs???
|
|
||||||
validate,
|
|
||||||
Configuration,
|
|
||||||
} from 'webpack';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -55,7 +51,7 @@ describe('extending generated webpack config', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('webpack-merge with user webpack config object', async () => {
|
test('webpack-merge with user webpack config object', async () => {
|
||||||
|
@ -83,7 +79,7 @@ describe('extending generated webpack config', () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const errors = validate(config);
|
const errors = validate(config);
|
||||||
expect(errors.length).toBe(0);
|
expect(errors).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('webpack-merge with custom strategy', async () => {
|
test('webpack-merge with custom strategy', async () => {
|
||||||
|
|
|
@ -7,13 +7,11 @@
|
||||||
|
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import PnpWebpackPlugin from 'pnp-webpack-plugin';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {Configuration, Loader} from 'webpack';
|
import {Configuration} from 'webpack';
|
||||||
import {Props} from '@docusaurus/types';
|
import {Props} from '@docusaurus/types';
|
||||||
import {
|
import {
|
||||||
getBabelLoader,
|
getJSLoader,
|
||||||
getCacheLoader,
|
|
||||||
getStyleLoaders,
|
getStyleLoaders,
|
||||||
getFileLoaderUtils,
|
getFileLoaderUtils,
|
||||||
getCustomBabelConfigFilePath,
|
getCustomBabelConfigFilePath,
|
||||||
|
@ -63,8 +61,14 @@ export function createBaseConfig(
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
minify: boolean = true,
|
minify: boolean = true,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
const {outDir, siteDir, baseUrl, generatedFilesDir, routesPaths} = props;
|
const {
|
||||||
|
outDir,
|
||||||
|
siteDir,
|
||||||
|
baseUrl,
|
||||||
|
generatedFilesDir,
|
||||||
|
routesPaths,
|
||||||
|
siteMetadata,
|
||||||
|
} = props;
|
||||||
const totalPages = routesPaths.length;
|
const totalPages = routesPaths.length;
|
||||||
const isProd = process.env.NODE_ENV === 'production';
|
const isProd = process.env.NODE_ENV === 'production';
|
||||||
const minimizeEnabled = minify && isProd && !isServer;
|
const minimizeEnabled = minify && isProd && !isServer;
|
||||||
|
@ -72,11 +76,32 @@ export function createBaseConfig(
|
||||||
|
|
||||||
const fileLoaderUtils = getFileLoaderUtils();
|
const fileLoaderUtils = getFileLoaderUtils();
|
||||||
|
|
||||||
|
const name = isServer ? 'server' : 'client';
|
||||||
|
const mode = isProd ? 'production' : 'development';
|
||||||
|
|
||||||
return {
|
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: {
|
output: {
|
||||||
// Use future version of asset emitting logic, which allows freeing memory of assets after emitting.
|
|
||||||
futureEmitAssets: true,
|
|
||||||
pathinfo: false,
|
pathinfo: false,
|
||||||
path: outDir,
|
path: outDir,
|
||||||
filename: isProd ? 'assets/js/[name].[contenthash:8].js' : '[name].js',
|
filename: isProd ? 'assets/js/[name].[contenthash:8].js' : '[name].js',
|
||||||
|
@ -89,8 +114,9 @@ export function createBaseConfig(
|
||||||
performance: {
|
performance: {
|
||||||
hints: false,
|
hints: false,
|
||||||
},
|
},
|
||||||
devtool: isProd ? false : 'cheap-module-eval-source-map',
|
devtool: isProd ? undefined : 'eval-cheap-module-source-map',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
unsafeCache: false, // not enabled, does not seem to improve perf much
|
||||||
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
|
extensions: ['.wasm', '.mjs', '.js', '.jsx', '.ts', '.tsx', '.json'],
|
||||||
symlinks: true,
|
symlinks: true,
|
||||||
roots: [
|
roots: [
|
||||||
|
@ -121,10 +147,8 @@ export function createBaseConfig(
|
||||||
'node_modules',
|
'node_modules',
|
||||||
path.resolve(fs.realpathSync(process.cwd()), 'node_modules'),
|
path.resolve(fs.realpathSync(process.cwd()), 'node_modules'),
|
||||||
],
|
],
|
||||||
plugins: [PnpWebpackPlugin],
|
|
||||||
},
|
},
|
||||||
resolveLoader: {
|
resolveLoader: {
|
||||||
plugins: [PnpWebpackPlugin.moduleLoader(module)],
|
|
||||||
modules: ['node_modules', path.join(siteDir, 'node_modules')],
|
modules: ['node_modules', path.join(siteDir, 'node_modules')],
|
||||||
},
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
|
@ -137,7 +161,7 @@ export function createBaseConfig(
|
||||||
splitChunks: isServer
|
splitChunks: isServer
|
||||||
? false
|
? 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,
|
name: false,
|
||||||
cacheGroups: {
|
cacheGroups: {
|
||||||
// disable the built-in cacheGroups
|
// disable the built-in cacheGroups
|
||||||
|
@ -153,7 +177,7 @@ export function createBaseConfig(
|
||||||
// See https://github.com/facebook/docusaurus/issues/2006
|
// See https://github.com/facebook/docusaurus/issues/2006
|
||||||
styles: {
|
styles: {
|
||||||
name: 'styles',
|
name: 'styles',
|
||||||
test: /\.css$/,
|
type: 'css/mini-extract',
|
||||||
chunks: `all`,
|
chunks: `all`,
|
||||||
enforce: true,
|
enforce: true,
|
||||||
priority: 50,
|
priority: 50,
|
||||||
|
@ -172,9 +196,11 @@ export function createBaseConfig(
|
||||||
test: /\.(j|t)sx?$/,
|
test: /\.(j|t)sx?$/,
|
||||||
exclude: excludeJS,
|
exclude: excludeJS,
|
||||||
use: [
|
use: [
|
||||||
getCacheLoader(isServer),
|
getJSLoader({
|
||||||
getBabelLoader(isServer, getCustomBabelConfigFilePath(siteDir)),
|
isServer,
|
||||||
].filter(Boolean) as Loader[],
|
babelOptions: getCustomBabelConfigFilePath(siteDir),
|
||||||
|
}),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: CSS_REGEX,
|
test: CSS_REGEX,
|
||||||
|
@ -191,7 +217,7 @@ export function createBaseConfig(
|
||||||
use: getStyleLoaders(isServer, {
|
use: getStyleLoaders(isServer, {
|
||||||
modules: {
|
modules: {
|
||||||
localIdentName: isProd
|
localIdentName: isProd
|
||||||
? `[local]_[hash:base64:4]`
|
? `[local]_[contenthash:base64:4]`
|
||||||
: `[local]_[path]`,
|
: `[local]_[path]`,
|
||||||
exportOnlyLocals: isServer,
|
exportOnlyLocals: isServer,
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,10 +24,14 @@ export default function createClientConfig(
|
||||||
const config = createBaseConfig(props, false, minify);
|
const config = createBaseConfig(props, false, minify);
|
||||||
|
|
||||||
const clientConfig = merge(config, {
|
const clientConfig = merge(config, {
|
||||||
|
// target: 'browserslist', // useless, disabled on purpose (errors on existing sites with no browserslist cfg)
|
||||||
entry: [
|
entry: [
|
||||||
// Instead of the default WebpackDevServer client, we use a custom one
|
// Instead of the default WebpackDevServer client, we use a custom one
|
||||||
// like CRA to bring better experience.
|
// 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'),
|
path.resolve(__dirname, '../client/clientEntry.js'),
|
||||||
].filter(Boolean) as string[],
|
].filter(Boolean) as string[],
|
||||||
optimization: {
|
optimization: {
|
||||||
|
@ -56,10 +60,6 @@ export default function createClientConfig(
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
stats.toJson('errors-only').errors.forEach((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,8 +15,10 @@ class ChunkAssetPlugin {
|
||||||
/* We modify webpack runtime to add an extra function called "__webpack_require__.gca"
|
/* 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.
|
that will allow us to get the corresponding chunk asset for a webpack chunk.
|
||||||
Pass it the chunkName or chunkId you want to load.
|
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
|
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 "/0a84b5e7.c8e35c7a.js" */
|
__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) => {
|
mainTemplate.hooks.requireExtensions.tap(pluginName, (source, chunk) => {
|
||||||
const chunkIdToName = chunk.getChunkMaps(false).name;
|
const chunkIdToName = chunk.getChunkMaps(false).name;
|
||||||
const chunkNameToId = Object.create(null);
|
const chunkNameToId = Object.create(null);
|
||||||
|
@ -25,16 +27,18 @@ class ChunkAssetPlugin {
|
||||||
chunkNameToId[chunkName] = chunkId;
|
chunkNameToId[chunkName] = chunkId;
|
||||||
});
|
});
|
||||||
const buf = [source];
|
const buf = [source];
|
||||||
buf.push('');
|
buf.push('// function to get chunk asset');
|
||||||
buf.push('// function to get chunk assets');
|
|
||||||
buf.push(
|
buf.push(
|
||||||
// If chunkName is passed, we convert it to chunk id
|
// If chunkName is passed, we convert it to chunk asset url
|
||||||
// Note that jsonpScriptSrc is an internal webpack function
|
// .p => public path url ("/" or "/baseUrl/")
|
||||||
`${
|
// .u(chunkId) => chunk asset url ("assets/js/x63b64xd.contentHash.js")
|
||||||
mainTemplate.requireFn
|
// not sure where this is documented, but this link was helpful: https://programmer.help/blogs/5d68849083e1a.html
|
||||||
}.gca = function(chunkId) { chunkId = ${JSON.stringify(
|
//
|
||||||
|
// 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,
|
chunkNameToId,
|
||||||
)}[chunkId]||chunkId; return jsonpScriptSrc(chunkId); };`,
|
)}[chunkId]||chunkId; return __webpack_require__.p + __webpack_require__.u(chunkId); };`,
|
||||||
);
|
);
|
||||||
return Template.asString(buf);
|
return Template.asString(buf);
|
||||||
});
|
});
|
||||||
|
|
|
@ -27,22 +27,13 @@
|
||||||
|
|
||||||
// Forked from https://github.com/johnagan/clean-webpack-plugin
|
// Forked from https://github.com/johnagan/clean-webpack-plugin
|
||||||
// Modified to optimize performance for Docusaurus specific use case
|
// Modified to optimize performance for Docusaurus specific use case
|
||||||
|
// More context: https://github.com/facebook/docusaurus/pull/1839
|
||||||
|
|
||||||
import {Compiler, Stats} from 'webpack';
|
import {Compiler, Stats} from 'webpack';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {sync as delSync} from 'del';
|
import {sync as delSync} from 'del';
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
/** @deprecated */
|
|
||||||
allowExternal?: unknown;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simulate the removal of files
|
|
||||||
*
|
|
||||||
* default: false
|
|
||||||
*/
|
|
||||||
dry?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write Logs to Console
|
* Write Logs to Console
|
||||||
* (Always enabled when dry is true)
|
* (Always enabled when dry is true)
|
||||||
|
@ -74,71 +65,19 @@ export interface Options {
|
||||||
* default: ['**\/*']
|
* default: ['**\/*']
|
||||||
*/
|
*/
|
||||||
cleanOnceBeforeBuildPatterns?: string[];
|
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 {
|
class CleanWebpackPlugin {
|
||||||
private readonly dry: boolean;
|
|
||||||
private readonly verbose: boolean;
|
private readonly verbose: boolean;
|
||||||
private readonly cleanStaleWebpackAssets: boolean;
|
private readonly cleanStaleWebpackAssets: boolean;
|
||||||
private readonly protectWebpackAssets: boolean;
|
private readonly protectWebpackAssets: boolean;
|
||||||
private readonly cleanAfterEveryBuildPatterns: string[];
|
|
||||||
private readonly cleanOnceBeforeBuildPatterns: string[];
|
private readonly cleanOnceBeforeBuildPatterns: string[];
|
||||||
private readonly dangerouslyAllowCleanPatternsOutsideProject: boolean;
|
|
||||||
private currentAssets: string[];
|
private currentAssets: string[];
|
||||||
private initialClean: boolean;
|
private initialClean: boolean;
|
||||||
private outputPath: string;
|
private outputPath: string;
|
||||||
|
|
||||||
constructor(options: Options = {}) {
|
constructor(options: Options = {}) {
|
||||||
if (typeof options !== 'object' || Array.isArray(options) === true) {
|
this.verbose = options.verbose === true || false;
|
||||||
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.cleanStaleWebpackAssets =
|
this.cleanStaleWebpackAssets =
|
||||||
options.cleanStaleWebpackAssets === true ||
|
options.cleanStaleWebpackAssets === true ||
|
||||||
|
@ -152,12 +91,6 @@ class CleanWebpackPlugin {
|
||||||
? options.protectWebpackAssets
|
? options.protectWebpackAssets
|
||||||
: true;
|
: true;
|
||||||
|
|
||||||
this.cleanAfterEveryBuildPatterns = Array.isArray(
|
|
||||||
options.cleanAfterEveryBuildPatterns,
|
|
||||||
)
|
|
||||||
? options.cleanAfterEveryBuildPatterns
|
|
||||||
: [];
|
|
||||||
|
|
||||||
this.cleanOnceBeforeBuildPatterns = Array.isArray(
|
this.cleanOnceBeforeBuildPatterns = Array.isArray(
|
||||||
options.cleanOnceBeforeBuildPatterns,
|
options.cleanOnceBeforeBuildPatterns,
|
||||||
)
|
)
|
||||||
|
@ -194,34 +127,17 @@ class CleanWebpackPlugin {
|
||||||
|
|
||||||
this.outputPath = compiler.options.output.path;
|
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;
|
const {hooks} = compiler;
|
||||||
|
|
||||||
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
|
if (this.cleanOnceBeforeBuildPatterns.length !== 0) {
|
||||||
if (hooks) {
|
hooks.compile.tap('clean-webpack-plugin', () => {
|
||||||
hooks.compile.tap('clean-webpack-plugin', () => {
|
this.handleInitial();
|
||||||
this.handleInitial();
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
compiler.plugin('compile', () => {
|
|
||||||
this.handleInitial();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hooks) {
|
hooks.done.tap('clean-webpack-plugin', (stats) => {
|
||||||
hooks.done.tap('clean-webpack-plugin', (stats) => {
|
this.handleDone(stats);
|
||||||
this.handleDone(stats);
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
compiler.plugin('done', (stats) => {
|
|
||||||
this.handleDone(stats);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,13 +174,10 @@ class CleanWebpackPlugin {
|
||||||
* Fetch Webpack's output asset files
|
* Fetch Webpack's output asset files
|
||||||
*/
|
*/
|
||||||
const statsAssets =
|
const statsAssets =
|
||||||
stats.toJson(
|
stats.toJson({
|
||||||
{
|
all: false,
|
||||||
all: false,
|
assets: true,
|
||||||
assets: true,
|
}).assets || [];
|
||||||
},
|
|
||||||
true,
|
|
||||||
).assets || [];
|
|
||||||
const assets = statsAssets.map((asset: {name: string}) => {
|
const assets = statsAssets.map((asset: {name: string}) => {
|
||||||
return asset.name;
|
return asset.name;
|
||||||
});
|
});
|
||||||
|
@ -275,9 +188,7 @@ class CleanWebpackPlugin {
|
||||||
* (relies on del's cwd: outputPath option)
|
* (relies on del's cwd: outputPath option)
|
||||||
*/
|
*/
|
||||||
const staleFiles = this.currentAssets.filter((previousAsset) => {
|
const staleFiles = this.currentAssets.filter((previousAsset) => {
|
||||||
const assetCurrent = assets.includes(previousAsset) === false;
|
return assets.includes(previousAsset) === false;
|
||||||
|
|
||||||
return assetCurrent;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -294,13 +205,6 @@ class CleanWebpackPlugin {
|
||||||
removePatterns.push(...staleFiles);
|
removePatterns.push(...staleFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove cleanAfterEveryBuildPatterns
|
|
||||||
*/
|
|
||||||
if (this.cleanAfterEveryBuildPatterns.length !== 0) {
|
|
||||||
removePatterns.push(...this.cleanAfterEveryBuildPatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removePatterns.length !== 0) {
|
if (removePatterns.length !== 0) {
|
||||||
this.removeFiles(removePatterns);
|
this.removeFiles(removePatterns);
|
||||||
}
|
}
|
||||||
|
@ -309,10 +213,10 @@ class CleanWebpackPlugin {
|
||||||
removeFiles(patterns: string[]): void {
|
removeFiles(patterns: string[]): void {
|
||||||
try {
|
try {
|
||||||
const deleted = delSync(patterns, {
|
const deleted = delSync(patterns, {
|
||||||
force: this.dangerouslyAllowCleanPatternsOutsideProject,
|
force: false,
|
||||||
// Change context to build directory
|
// Change context to build directory
|
||||||
cwd: this.outputPath,
|
cwd: this.outputPath,
|
||||||
dryRun: this.dry,
|
dryRun: false,
|
||||||
dot: true,
|
dot: true,
|
||||||
ignore: this.protectWebpackAssets ? this.currentAssets : [],
|
ignore: this.protectWebpackAssets ? this.currentAssets : [],
|
||||||
});
|
});
|
||||||
|
@ -324,15 +228,13 @@ class CleanWebpackPlugin {
|
||||||
deleted.forEach((file) => {
|
deleted.forEach((file) => {
|
||||||
const filename = path.relative(process.cwd(), file);
|
const filename = path.relative(process.cwd(), file);
|
||||||
|
|
||||||
const message = this.dry ? 'dry' : 'removed';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use console.warn over .log
|
* Use console.warn over .log
|
||||||
* https://github.com/webpack/webpack/issues/1904
|
* https://github.com/webpack/webpack/issues/1904
|
||||||
* https://github.com/johnagan/clean-webpack-plugin/issues/11
|
* https://github.com/johnagan/clean-webpack-plugin/issues/11
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn(`clean-webpack-plugin: ${message} ${filename}`);
|
console.warn(`clean-webpack-plugin: removed ${filename}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} 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 {createBaseConfig} from './base';
|
||||||
import WaitPlugin from './plugins/WaitPlugin';
|
import WaitPlugin from './plugins/WaitPlugin';
|
||||||
import LogPlugin from './plugins/LogPlugin';
|
import LogPlugin from './plugins/LogPlugin';
|
||||||
|
import {NODE_MAJOR_VERSION, NODE_MINOR_VERSION} from '../constants';
|
||||||
|
|
||||||
export default function createServerConfig({
|
export default function createServerConfig({
|
||||||
props,
|
props,
|
||||||
|
@ -43,6 +44,7 @@ export default function createServerConfig({
|
||||||
return ssgPath;
|
return ssgPath;
|
||||||
});
|
});
|
||||||
const serverConfig = merge(config, {
|
const serverConfig = merge(config, {
|
||||||
|
target: `node${NODE_MAJOR_VERSION}.${NODE_MINOR_VERSION}`,
|
||||||
entry: {
|
entry: {
|
||||||
main: path.resolve(__dirname, '../client/serverEntry.js'),
|
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)
|
// Workaround for Webpack 4 Bug (https://github.com/webpack/webpack/issues/6522)
|
||||||
globalObject: 'this',
|
globalObject: 'this',
|
||||||
},
|
},
|
||||||
target: 'node',
|
|
||||||
plugins: [
|
plugins: [
|
||||||
// Wait until manifest from client bundle is generated
|
// Wait until manifest from client bundle is generated
|
||||||
new WaitPlugin({
|
new WaitPlugin({
|
||||||
|
|
|
@ -6,20 +6,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||||
import env from 'std-env';
|
import {
|
||||||
import merge from 'webpack-merge';
|
mergeWithCustomize,
|
||||||
|
customizeArray,
|
||||||
|
customizeObject,
|
||||||
|
CustomizeRule,
|
||||||
|
} from 'webpack-merge';
|
||||||
import webpack, {
|
import webpack, {
|
||||||
Configuration,
|
Configuration,
|
||||||
Loader,
|
|
||||||
NewLoader,
|
|
||||||
Plugin,
|
|
||||||
RuleSetRule,
|
RuleSetRule,
|
||||||
Stats,
|
WebpackPluginInstance,
|
||||||
} from 'webpack';
|
} from 'webpack';
|
||||||
import fs from 'fs-extra';
|
import fs from 'fs-extra';
|
||||||
import TerserPlugin from 'terser-webpack-plugin';
|
import TerserPlugin from 'terser-webpack-plugin';
|
||||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
|
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin';
|
||||||
import CleanCss from 'clean-css';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
@ -28,13 +28,13 @@ import {
|
||||||
ConfigureWebpackFn,
|
ConfigureWebpackFn,
|
||||||
ConfigurePostCssFn,
|
ConfigurePostCssFn,
|
||||||
PostCssOptions,
|
PostCssOptions,
|
||||||
|
ConfigureWebpackUtils,
|
||||||
} from '@docusaurus/types';
|
} from '@docusaurus/types';
|
||||||
import CssNanoPreset from '@docusaurus/cssnano-preset';
|
|
||||||
import {version as cacheLoaderVersion} from 'cache-loader/package.json';
|
|
||||||
import {
|
import {
|
||||||
BABEL_CONFIG_FILE_NAME,
|
BABEL_CONFIG_FILE_NAME,
|
||||||
OUTPUT_STATIC_ASSETS_DIR_NAME,
|
OUTPUT_STATIC_ASSETS_DIR_NAME,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
|
import {memoize} from 'lodash';
|
||||||
|
|
||||||
// Utility method to get style loaders
|
// Utility method to get style loaders
|
||||||
export function getStyleLoaders(
|
export function getStyleLoaders(
|
||||||
|
@ -42,24 +42,36 @@ export function getStyleLoaders(
|
||||||
cssOptions: {
|
cssOptions: {
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
} = {},
|
} = {},
|
||||||
): Loader[] {
|
): RuleSetRule[] {
|
||||||
if (isServer) {
|
if (isServer) {
|
||||||
return [
|
return cssOptions.modules
|
||||||
cssOptions.modules
|
? [
|
||||||
? {
|
{
|
||||||
loader: require.resolve('css-loader'),
|
loader: require.resolve('css-loader'),
|
||||||
options: cssOptions,
|
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';
|
return [
|
||||||
const loaders = [
|
|
||||||
{
|
{
|
||||||
loader: MiniCssExtractPlugin.loader,
|
loader: MiniCssExtractPlugin.loader,
|
||||||
options: {
|
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(
|
export function getCustomBabelConfigFilePath(
|
||||||
|
@ -141,16 +135,50 @@ export function getBabelOptions({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBabelLoader(
|
// Name is generic on purpose
|
||||||
isServer: boolean,
|
// we want to support multiple js loader implementations (babel + esbuild)
|
||||||
babelOptions?: TransformOptions | string,
|
export function getJSLoader({
|
||||||
): Loader {
|
isServer,
|
||||||
|
babelOptions,
|
||||||
|
}: {
|
||||||
|
isServer: boolean;
|
||||||
|
babelOptions?: TransformOptions | string;
|
||||||
|
}): RuleSetRule {
|
||||||
return {
|
return {
|
||||||
loader: require.resolve('babel-loader'),
|
loader: require.resolve('babel-loader'),
|
||||||
options: getBabelOptions({isServer, babelOptions}),
|
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
|
* Helper function to modify webpack config
|
||||||
* @param configureWebpack a webpack config or a function to modify config
|
* @param configureWebpack a webpack config or a function to modify config
|
||||||
|
@ -164,15 +192,21 @@ export function applyConfigureWebpack(
|
||||||
isServer: boolean,
|
isServer: boolean,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
// Export some utility functions
|
// Export some utility functions
|
||||||
const utils = {
|
const utils: ConfigureWebpackUtils = {
|
||||||
getStyleLoaders,
|
getStyleLoaders,
|
||||||
getCacheLoader,
|
getJSLoader,
|
||||||
getBabelLoader,
|
getBabelLoader: getBabelLoaderDeprecated,
|
||||||
|
getCacheLoader: getCacheLoaderDeprecated,
|
||||||
};
|
};
|
||||||
if (typeof configureWebpack === 'function') {
|
if (typeof configureWebpack === 'function') {
|
||||||
const {mergeStrategy, ...res} = configureWebpack(config, isServer, utils);
|
const {mergeStrategy, ...res} = configureWebpack(config, isServer, utils);
|
||||||
if (res && typeof res === 'object') {
|
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;
|
return config;
|
||||||
|
@ -182,13 +216,13 @@ export function applyConfigurePostCss(
|
||||||
configurePostCss: NonNullable<ConfigurePostCssFn>,
|
configurePostCss: NonNullable<ConfigurePostCssFn>,
|
||||||
config: Configuration,
|
config: Configuration,
|
||||||
): Configuration {
|
): Configuration {
|
||||||
type LocalPostCSSLoader = Loader & {
|
type LocalPostCSSLoader = unknown & {
|
||||||
options: {postcssOptions: PostCssOptions};
|
options: {postcssOptions: PostCssOptions};
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO not ideal heuristic but good enough for our usecase?
|
// TODO not ideal heuristic but good enough for our usecase?
|
||||||
function isPostCssLoader(loader: Loader): loader is LocalPostCSSLoader {
|
function isPostCssLoader(loader: unknown): loader is LocalPostCSSLoader {
|
||||||
return !!(loader as NewLoader)?.options?.postcssOptions;
|
return !!(loader as any)?.options?.postcssOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does not handle all edge cases, but good enough for now
|
// 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;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://webpack.js.org/configuration/stats/#statswarningsfilter
|
export function compile(config: Configuration[]): Promise<void> {
|
||||||
// @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> {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const compiler = webpack(config);
|
const compiler = webpack(config);
|
||||||
compiler.run((err, stats) => {
|
compiler.run((err, stats) => {
|
||||||
if (err) {
|
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
|
// let plugins consume all the stats
|
||||||
const allStats = stats?.toJson('errors-warnings');
|
const errorsWarnings = stats?.toJson('errors-warnings');
|
||||||
if (stats?.hasErrors()) {
|
if (stats?.hasErrors()) {
|
||||||
allStats.errors.forEach((e) => {
|
|
||||||
console.error(e);
|
|
||||||
});
|
|
||||||
reject(new Error('Failed to compile with errors.'));
|
reject(new Error('Failed to compile with errors.'));
|
||||||
}
|
}
|
||||||
if (stats?.hasWarnings()) {
|
if (errorsWarnings && stats?.hasWarnings()) {
|
||||||
// Custom filtering warnings (see https://github.com/webpack/webpack/issues/7841).
|
errorsWarnings.warnings?.forEach((warning) => {
|
||||||
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) => {
|
|
||||||
console.warn(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 = {
|
type FileLoaderUtils = {
|
||||||
loaders: {
|
loaders: {
|
||||||
file: (options: {folder: AssetFolder}) => Loader;
|
file: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||||
url: (options: {folder: AssetFolder}) => Loader;
|
url: (options: {folder: AssetFolder}) => RuleSetRule;
|
||||||
inlineMarkdownImageFileLoader: string;
|
inlineMarkdownImageFileLoader: string;
|
||||||
inlineMarkdownLinkFileLoader: string;
|
inlineMarkdownLinkFileLoader: string;
|
||||||
};
|
};
|
||||||
|
@ -298,7 +311,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
||||||
const fileLoaderFileName = (folder: AssetFolder) =>
|
const fileLoaderFileName = (folder: AssetFolder) =>
|
||||||
`${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`;
|
`${OUTPUT_STATIC_ASSETS_DIR_NAME}/${folder}/[name]-[hash].[ext]`;
|
||||||
|
|
||||||
const loaders = {
|
const loaders: FileLoaderUtils['loaders'] = {
|
||||||
file: (options: {folder: AssetFolder}) => {
|
file: (options: {folder: AssetFolder}) => {
|
||||||
return {
|
return {
|
||||||
loader: require.resolve(`file-loader`),
|
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
|
* Loads image assets, inlines images via a data URI if they are below
|
||||||
* the size threshold
|
* the size threshold
|
||||||
*/
|
*/
|
||||||
images: (): RuleSetRule => {
|
images: () => {
|
||||||
return {
|
return {
|
||||||
use: [loaders.url({folder: 'images'})],
|
use: [loaders.url({folder: 'images'})],
|
||||||
test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/,
|
test: /\.(ico|jpg|jpeg|png|gif|webp)(\?.*)?$/,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
fonts: (): RuleSetRule => {
|
fonts: () => {
|
||||||
return {
|
return {
|
||||||
use: [loaders.url({folder: 'fonts'})],
|
use: [loaders.url({folder: 'fonts'})],
|
||||||
test: /\.(woff|woff2|eot|ttf|otf)$/,
|
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
|
* Loads audio and video and inlines them via a data URI if they are below
|
||||||
* the size threshold
|
* the size threshold
|
||||||
*/
|
*/
|
||||||
media: (): RuleSetRule => {
|
media: () => {
|
||||||
return {
|
return {
|
||||||
use: [loaders.url({folder: 'medias'})],
|
use: [loaders.url({folder: 'medias'})],
|
||||||
test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/,
|
test: /\.(mp4|webm|ogv|wav|mp3|m4a|aac|oga|flac)$/,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
svg: (): RuleSetRule => {
|
svg: () => {
|
||||||
return {
|
return {
|
||||||
test: /\.svg?$/,
|
test: /\.svg?$/,
|
||||||
oneOf: [
|
oneOf: [
|
||||||
|
@ -383,7 +396,7 @@ export function getFileLoaderUtils(): FileLoaderUtils {
|
||||||
// We don't want to use SVGR loader for non-React source code
|
// We don't want to use SVGR loader for non-React source code
|
||||||
// ie we don't want to use SVGR for CSS files...
|
// ie we don't want to use SVGR for CSS files...
|
||||||
issuer: {
|
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 {
|
return {
|
||||||
use: [loaders.file({folder: 'files'})],
|
use: [loaders.file({folder: 'files'})],
|
||||||
test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/,
|
test: /\.(pdf|doc|docx|xls|xlsx|zip|rar)$/,
|
||||||
|
@ -476,12 +489,12 @@ function getTerserParallel() {
|
||||||
return terserParallel;
|
return terserParallel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMinimizer(useSimpleCssMinifier = false): Plugin[] {
|
export function getMinimizer(
|
||||||
|
useSimpleCssMinifier = false,
|
||||||
|
): WebpackPluginInstance[] {
|
||||||
const minimizer = [
|
const minimizer = [
|
||||||
new TerserPlugin({
|
new TerserPlugin({
|
||||||
cache: true,
|
|
||||||
parallel: getTerserParallel(),
|
parallel: getTerserParallel(),
|
||||||
sourceMap: false,
|
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
parse: {
|
parse: {
|
||||||
// we want uglify-js to parse ecma 8 code. However, we don't want it
|
// 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) {
|
if (useSimpleCssMinifier) {
|
||||||
minimizer.push(
|
minimizer.push(new CssMinimizerPlugin());
|
||||||
new OptimizeCSSAssetsPlugin({
|
|
||||||
cssProcessorPluginOptions: {
|
|
||||||
preset: 'default',
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
minimizer.push(
|
minimizer.push(
|
||||||
...[
|
// Using the array syntax to add 2 minimizers
|
||||||
new OptimizeCSSAssetsPlugin({
|
// see https://github.com/webpack-contrib/css-minimizer-webpack-plugin#array
|
||||||
cssProcessorPluginOptions: {
|
new CssMinimizerPlugin({
|
||||||
preset: CssNanoPreset,
|
minimizerOptions: [
|
||||||
|
// CssNano options
|
||||||
|
{
|
||||||
|
preset: require.resolve('@docusaurus/cssnano-preset'),
|
||||||
},
|
},
|
||||||
}),
|
// CleanCss options
|
||||||
new OptimizeCSSAssetsPlugin({
|
{
|
||||||
cssProcessor: CleanCss,
|
|
||||||
cssProcessorOptions: {
|
|
||||||
inline: false,
|
inline: false,
|
||||||
level: {
|
level: {
|
||||||
1: {
|
1: {
|
||||||
|
@ -540,8 +547,12 @@ export function getMinimizer(useSimpleCssMinifier = false): Plugin[] {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
],
|
||||||
],
|
minify: [
|
||||||
|
CssMinimizerPlugin.cssnanoMinify,
|
||||||
|
CssMinimizerPlugin.cleanCssMinify,
|
||||||
|
],
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"loader-utils": "^1.2.3",
|
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"node-vibrant": "^3.1.5",
|
"node-vibrant": "^3.1.5",
|
||||||
"sharp": "^0.27.1"
|
"sharp": "^0.27.1"
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const loaderUtils = require('loader-utils');
|
|
||||||
const lqip = require('./lqip');
|
const lqip = require('./lqip');
|
||||||
|
|
||||||
module.exports = function (contentBuffer) {
|
module.exports = function (contentBuffer) {
|
||||||
|
@ -15,7 +14,7 @@ module.exports = function (contentBuffer) {
|
||||||
const callback = this.async();
|
const callback = this.async();
|
||||||
const imgPath = this.resourcePath;
|
const imgPath = this.resourcePath;
|
||||||
|
|
||||||
const config = loaderUtils.getOptions(this) || {};
|
const config = this.getOptions() || {};
|
||||||
config.base64 = 'base64' in config ? config.base64 : true;
|
config.base64 = 'base64' in config ? config.base64 : true;
|
||||||
config.palette = 'palette' in config ? config.palette : false;
|
config.palette = 'palette' in config ? config.palette : false;
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
/* Advanced Options */
|
/* Advanced Options */
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true, // @types/webpack and webpack/types.d.ts are not the same thing
|
||||||
|
|
||||||
/* Use tslib */
|
/* Use tslib */
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
|
|
|
@ -398,7 +398,6 @@ type Props = {
|
||||||
postBodyTags: string;
|
postBodyTags: string;
|
||||||
routesPaths: string[];
|
routesPaths: string[];
|
||||||
plugins: Plugin<any>[];
|
plugins: Plugin<any>[];
|
||||||
stats: Stats.ToJsonOutput;
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -408,13 +407,11 @@ Example:
|
||||||
module.exports = function (context, options) {
|
module.exports = function (context, options) {
|
||||||
return {
|
return {
|
||||||
name: 'docusaurus-plugin',
|
name: 'docusaurus-plugin',
|
||||||
async postBuild({siteConfig = {}, routesPaths = [], outDir, stats}) {
|
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
|
||||||
// Print out to console all the rendered routes.
|
// Print out to console all the rendered routes.
|
||||||
routesPaths.map((route) => {
|
routesPaths.map((route) => {
|
||||||
console.log(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]
|
[build]
|
||||||
base = "/"
|
command = "yarn --cwd .. build:packages && yarn build"
|
||||||
command = "yarn workspace docusaurus-2-website netlify:build:production"
|
|
||||||
publish = "website/build"
|
publish = "website/build"
|
||||||
|
|
||||||
# we build deploy previews with a /build/ baseUrl on purpose
|
[build.environment]
|
||||||
# permits to test that baseUrl works fine (this often breaks!)
|
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]
|
[context.deploy-preview]
|
||||||
command = "yarn workspace docusaurus-2-website netlify:build:deployPreview"
|
command = "yarn --cwd .. build:packages && yarn netlify:build:deployPreview"
|
||||||
publish = "website/build"
|
|
||||||
|
|
||||||
|
[[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",
|
"@docusaurus/theme-live-codeblock": "2.0.0-alpha.74",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"color": "^3.1.3",
|
"color": "^3.1.3",
|
||||||
|
"netlify-plugin-cache": "^1.0.3",
|
||||||
"npm-to-yarn": "^1.0.0-2",
|
"npm-to-yarn": "^1.0.0-2",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
|
|
Loading…
Add table
Reference in a new issue