mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-03 16:59:06 +02:00
refactor: convert all fs methods to async (#6725)
* refactor: convert all fs methods to async * fix snap
This commit is contained in:
parent
c0b3c9af65
commit
c6d0d812eb
46 changed files with 518 additions and 429 deletions
|
@ -36,7 +36,7 @@ const {
|
|||
*
|
||||
* cache data is stored in `~/.config/configstore/update-notifier-@docusaurus`
|
||||
*/
|
||||
function beforeCli() {
|
||||
async function beforeCli() {
|
||||
const notifier = updateNotifier({
|
||||
pkg: {
|
||||
name,
|
||||
|
@ -98,7 +98,9 @@ function beforeCli() {
|
|||
.filter((p) => p.startsWith('@docusaurus'))
|
||||
.map((p) => p.concat('@latest'))
|
||||
.join(' ');
|
||||
const isYarnUsed = fs.existsSync(path.resolve(process.cwd(), 'yarn.lock'));
|
||||
const isYarnUsed = await fs.pathExists(
|
||||
path.resolve(process.cwd(), 'yarn.lock'),
|
||||
);
|
||||
const upgradeCommand = isYarnUsed
|
||||
? `yarn upgrade ${siteDocusaurusPackagesForUpdate}`
|
||||
: `npm i ${siteDocusaurusPackagesForUpdate}`;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// @ts-check
|
||||
|
||||
import logger from '@docusaurus/logger';
|
||||
import fs from 'fs';
|
||||
import fs from 'fs-extra';
|
||||
import cli from 'commander';
|
||||
import {createRequire} from 'module';
|
||||
import {
|
||||
|
@ -25,9 +25,9 @@ import {
|
|||
} from '../lib/index.js';
|
||||
import beforeCli from './beforeCli.mjs';
|
||||
|
||||
beforeCli();
|
||||
await beforeCli();
|
||||
|
||||
const resolveDir = (dir = '.') => fs.realpathSync(dir);
|
||||
const resolveDir = (dir = '.') => fs.realpath(dir);
|
||||
|
||||
cli
|
||||
.version(createRequire(import.meta.url)('../package.json').version)
|
||||
|
@ -56,8 +56,8 @@ cli
|
|||
'--no-minify',
|
||||
'build website without minimizing JS bundles (default: false)',
|
||||
)
|
||||
.action((siteDir, {bundleAnalyzer, config, outDir, locale, minify}) => {
|
||||
build(resolveDir(siteDir), {
|
||||
.action(async (siteDir, {bundleAnalyzer, config, outDir, locale, minify}) => {
|
||||
build(await resolveDir(siteDir), {
|
||||
bundleAnalyzer,
|
||||
outDir,
|
||||
config,
|
||||
|
@ -74,8 +74,14 @@ cli
|
|||
'copy TypeScript theme files when possible (default: false)',
|
||||
)
|
||||
.option('--danger', 'enable swizzle for internal component of themes')
|
||||
.action((themeName, componentName, siteDir, {typescript, danger}) => {
|
||||
swizzle(resolveDir(siteDir), themeName, componentName, typescript, danger);
|
||||
.action(async (themeName, componentName, siteDir, {typescript, danger}) => {
|
||||
swizzle(
|
||||
await resolveDir(siteDir),
|
||||
themeName,
|
||||
componentName,
|
||||
typescript,
|
||||
danger,
|
||||
);
|
||||
});
|
||||
|
||||
cli
|
||||
|
@ -97,8 +103,8 @@ cli
|
|||
'--skip-build',
|
||||
'skip building website before deploy it (default: false)',
|
||||
)
|
||||
.action((siteDir, {outDir, skipBuild, config}) => {
|
||||
deploy(resolveDir(siteDir), {
|
||||
.action(async (siteDir, {outDir, skipBuild, config}) => {
|
||||
deploy(await resolveDir(siteDir), {
|
||||
outDir,
|
||||
config,
|
||||
skipBuild,
|
||||
|
@ -124,17 +130,19 @@ cli
|
|||
'--poll [interval]',
|
||||
'use polling rather than watching for reload (default: false). Can specify a poll interval in milliseconds',
|
||||
)
|
||||
.action((siteDir, {port, host, locale, config, hotOnly, open, poll}) => {
|
||||
start(resolveDir(siteDir), {
|
||||
port,
|
||||
host,
|
||||
locale,
|
||||
config,
|
||||
hotOnly,
|
||||
open,
|
||||
poll,
|
||||
});
|
||||
});
|
||||
.action(
|
||||
async (siteDir, {port, host, locale, config, hotOnly, open, poll}) => {
|
||||
start(await resolveDir(siteDir), {
|
||||
port,
|
||||
host,
|
||||
locale,
|
||||
config,
|
||||
hotOnly,
|
||||
open,
|
||||
poll,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
cli
|
||||
.command('serve [siteDir]')
|
||||
|
@ -151,7 +159,7 @@ cli
|
|||
.option('--build', 'build website before serving (default: false)')
|
||||
.option('-h, --host <host>', 'use specified host (default: localhost)')
|
||||
.action(
|
||||
(
|
||||
async (
|
||||
siteDir,
|
||||
{
|
||||
dir = 'build',
|
||||
|
@ -161,7 +169,7 @@ cli
|
|||
config,
|
||||
},
|
||||
) => {
|
||||
serve(resolveDir(siteDir), {
|
||||
serve(await resolveDir(siteDir), {
|
||||
dir,
|
||||
port,
|
||||
build: buildSite,
|
||||
|
@ -174,8 +182,8 @@ cli
|
|||
cli
|
||||
.command('clear [siteDir]')
|
||||
.description('Remove build artifacts.')
|
||||
.action((siteDir) => {
|
||||
clear(resolveDir(siteDir));
|
||||
.action(async (siteDir) => {
|
||||
clear(await resolveDir(siteDir));
|
||||
});
|
||||
|
||||
cli
|
||||
|
@ -198,11 +206,11 @@ cli
|
|||
'allows to init new written messages with a given prefix. This might help you to highlight untranslated message to make them stand out in the UI',
|
||||
)
|
||||
.action(
|
||||
(
|
||||
async (
|
||||
siteDir,
|
||||
{locale = undefined, override = false, messagePrefix = '', config},
|
||||
) => {
|
||||
writeTranslations(resolveDir(siteDir), {
|
||||
writeTranslations(await resolveDir(siteDir), {
|
||||
locale,
|
||||
override,
|
||||
config,
|
||||
|
@ -219,8 +227,8 @@ cli
|
|||
"keep the headings' casing, otherwise make all lowercase (default: false)",
|
||||
)
|
||||
.option('--overwrite', 'overwrite existing heading IDs (default: false)')
|
||||
.action((siteDir, files, options) =>
|
||||
writeHeadingIds(resolveDir(siteDir), files, options),
|
||||
.action(async (siteDir, files, options) =>
|
||||
writeHeadingIds(await resolveDir(siteDir), files, options),
|
||||
);
|
||||
|
||||
cli.arguments('<command>').action((cmd) => {
|
||||
|
@ -246,7 +254,7 @@ function isInternalCommand(command) {
|
|||
|
||||
async function run() {
|
||||
if (!isInternalCommand(process.argv.slice(2)[0])) {
|
||||
await externalCommand(cli, resolveDir('.'));
|
||||
await externalCommand(cli, await resolveDir('.'));
|
||||
}
|
||||
|
||||
cli.parse(process.argv);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
"boxen": "^5.1.2",
|
||||
"chokidar": "^3.5.3",
|
||||
"clean-css": "^5.2.4",
|
||||
"combine-promises": "^1.1.0",
|
||||
"commander": "^5.1.0",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
"core-js": "^3.21.1",
|
||||
|
|
|
@ -130,7 +130,7 @@ async function buildLocale({
|
|||
'client-manifest.json',
|
||||
);
|
||||
let clientConfig: Configuration = merge(
|
||||
createClientConfig(props, cliOptions.minify),
|
||||
await createClientConfig(props, cliOptions.minify),
|
||||
{
|
||||
plugins: [
|
||||
// Remove/clean build folders before building bundles.
|
||||
|
@ -148,23 +148,26 @@ async function buildLocale({
|
|||
|
||||
const allCollectedLinks: Record<string, string[]> = {};
|
||||
|
||||
let serverConfig: Configuration = createServerConfig({
|
||||
let serverConfig: Configuration = await createServerConfig({
|
||||
props,
|
||||
onLinksCollected: (staticPagePath, links) => {
|
||||
allCollectedLinks[staticPagePath] = links;
|
||||
},
|
||||
});
|
||||
|
||||
serverConfig = merge(serverConfig, {
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: staticDirectories
|
||||
.map((dir) => path.resolve(siteDir, dir))
|
||||
.filter(fs.existsSync)
|
||||
.map((dir) => ({from: dir, to: outDir})),
|
||||
}),
|
||||
],
|
||||
});
|
||||
if (staticDirectories.length > 0) {
|
||||
await Promise.all(staticDirectories.map((dir) => fs.ensureDir(dir)));
|
||||
|
||||
serverConfig = merge(serverConfig, {
|
||||
plugins: [
|
||||
new CopyWebpackPlugin({
|
||||
patterns: staticDirectories
|
||||
.map((dir) => path.resolve(siteDir, dir))
|
||||
.map((dir) => ({from: dir, to: outDir})),
|
||||
}),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// Plugin Lifecycle - configureWebpack and configurePostCss.
|
||||
plugins.forEach((plugin) => {
|
||||
|
|
|
@ -107,7 +107,7 @@ export default async function start(
|
|||
? (cliOptions.poll as number)
|
||||
: undefined,
|
||||
};
|
||||
const httpsConfig = getHttpsConfig();
|
||||
const httpsConfig = await getHttpsConfig();
|
||||
const fsWatcher = chokidar.watch(pathsToWatch, {
|
||||
cwd: siteDir,
|
||||
ignoreInitial: true,
|
||||
|
@ -118,7 +118,7 @@ export default async function start(
|
|||
fsWatcher.on(event, reload),
|
||||
);
|
||||
|
||||
let config: webpack.Configuration = merge(createClientConfig(props), {
|
||||
let config: webpack.Configuration = merge(await createClientConfig(props), {
|
||||
infrastructureLogging: {
|
||||
// Reduce log verbosity, see https://github.com/facebook/docusaurus/pull/5420#issuecomment-906613105
|
||||
level: 'warn',
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-restricted-properties */
|
||||
import logger from '@docusaurus/logger';
|
||||
import fs from 'fs-extra';
|
||||
import importFresh from 'import-fresh';
|
||||
|
|
|
@ -97,7 +97,7 @@ Available locales are: ${context.i18n.locales.join(',')}.`,
|
|||
|
||||
const babelOptions = getBabelOptions({
|
||||
isServer: true,
|
||||
babelOptions: getCustomBabelConfigFilePath(siteDir),
|
||||
babelOptions: await getCustomBabelConfigFilePath(siteDir),
|
||||
});
|
||||
const extractedCodeTranslations = await extractSiteSourceCodeTranslations(
|
||||
siteDir,
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
} from '@docusaurus/utils';
|
||||
import {getAllFinalRoutes} from './utils';
|
||||
import path from 'path';
|
||||
import combinePromises from 'combine-promises';
|
||||
|
||||
function toReactRouterRoutes(routes: RouteConfig[]): RRRouteConfig[] {
|
||||
// @ts-expect-error: types incompatible???
|
||||
|
@ -158,9 +159,9 @@ export function getBrokenLinksErrorMessage(
|
|||
);
|
||||
}
|
||||
|
||||
function isExistingFile(filePath: string) {
|
||||
async function isExistingFile(filePath: string) {
|
||||
try {
|
||||
return fs.statSync(filePath).isFile();
|
||||
return (await fs.stat(filePath)).isFile();
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
@ -177,8 +178,7 @@ export async function filterExistingFileLinks({
|
|||
outDir: string;
|
||||
allCollectedLinks: Record<string, string[]>;
|
||||
}): Promise<Record<string, string[]>> {
|
||||
// not easy to make this async :'(
|
||||
function linkFileExists(link: string): boolean {
|
||||
async function linkFileExists(link: string) {
|
||||
// /baseUrl/javadoc/ -> /outDir/javadoc
|
||||
const baseFilePath = removeSuffix(
|
||||
`${outDir}/${removePrefix(link, baseUrl)}`,
|
||||
|
@ -194,11 +194,22 @@ export async function filterExistingFileLinks({
|
|||
filePathsToTry.push(path.join(baseFilePath, 'index.html'));
|
||||
}
|
||||
|
||||
return filePathsToTry.some(isExistingFile);
|
||||
for (const file of filePathsToTry) {
|
||||
if (await isExistingFile(file)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return _.mapValues(allCollectedLinks, (links) =>
|
||||
links.filter((link) => !linkFileExists(link)),
|
||||
return combinePromises(
|
||||
_.mapValues(allCollectedLinks, async (links) =>
|
||||
(
|
||||
await Promise.all(
|
||||
links.map(async (link) => ((await linkFileExists(link)) ? '' : link)),
|
||||
)
|
||||
).filter(Boolean),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import {validateConfig} from './configValidation';
|
|||
export default async function loadConfig(
|
||||
configPath: string,
|
||||
): Promise<DocusaurusConfig> {
|
||||
if (!fs.existsSync(configPath)) {
|
||||
if (!(await fs.pathExists(configPath))) {
|
||||
throw new Error(`Config file at "${configPath}" not found.`);
|
||||
}
|
||||
|
||||
|
|
|
@ -403,10 +403,12 @@ ${Object.keys(registry)
|
|||
|
||||
// Version metadata.
|
||||
const siteMetadata: DocusaurusSiteMetadata = {
|
||||
docusaurusVersion: getPackageJsonVersion(
|
||||
docusaurusVersion: (await getPackageJsonVersion(
|
||||
path.join(__dirname, '../../package.json'),
|
||||
)!,
|
||||
siteVersion: getPackageJsonVersion(path.join(siteDir, 'package.json')),
|
||||
))!,
|
||||
siteVersion: await getPackageJsonVersion(
|
||||
path.join(siteDir, 'package.json'),
|
||||
),
|
||||
pluginVersions: {},
|
||||
};
|
||||
plugins
|
||||
|
|
|
@ -133,9 +133,9 @@ export default async function initPlugins({
|
|||
// siteDir's package.json declares the dependency on these plugins.
|
||||
const pluginRequire = createRequire(context.siteConfigPath);
|
||||
|
||||
function doGetPluginVersion(
|
||||
async function doGetPluginVersion(
|
||||
normalizedPluginConfig: NormalizedPluginConfig,
|
||||
): DocusaurusPluginVersionInformation {
|
||||
): Promise<DocusaurusPluginVersionInformation> {
|
||||
// get plugin version
|
||||
if (normalizedPluginConfig.pluginModule?.path) {
|
||||
const pluginPath = pluginRequire.resolve(
|
||||
|
@ -187,7 +187,7 @@ export default async function initPlugins({
|
|||
pluginRequire,
|
||||
);
|
||||
const pluginVersion: DocusaurusPluginVersionInformation =
|
||||
doGetPluginVersion(normalizedPluginConfig);
|
||||
await doGetPluginVersion(normalizedPluginConfig);
|
||||
const pluginOptions = doValidatePluginOptions(normalizedPluginConfig);
|
||||
|
||||
// Side-effect: merge the normalized theme config in the original one
|
||||
|
|
|
@ -10,10 +10,10 @@ import fs from 'fs-extra';
|
|||
import themeAlias from '../alias';
|
||||
|
||||
describe('themeAlias', () => {
|
||||
test('valid themePath 1 with components', () => {
|
||||
test('valid themePath 1 with components', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'theme-1');
|
||||
const alias = themeAlias(themePath, true);
|
||||
const alias = await themeAlias(themePath, true);
|
||||
// Testing entries, because order matters!
|
||||
expect(Object.entries(alias)).toEqual(
|
||||
Object.entries({
|
||||
|
@ -26,10 +26,10 @@ describe('themeAlias', () => {
|
|||
expect(alias).not.toEqual({});
|
||||
});
|
||||
|
||||
test('valid themePath 1 with components without original', () => {
|
||||
test('valid themePath 1 with components without original', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'theme-1');
|
||||
const alias = themeAlias(themePath, false);
|
||||
const alias = await themeAlias(themePath, false);
|
||||
// Testing entries, because order matters!
|
||||
expect(Object.entries(alias)).toEqual(
|
||||
Object.entries({
|
||||
|
@ -40,10 +40,10 @@ describe('themeAlias', () => {
|
|||
expect(alias).not.toEqual({});
|
||||
});
|
||||
|
||||
test('valid themePath 2 with components', () => {
|
||||
test('valid themePath 2 with components', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'theme-2');
|
||||
const alias = themeAlias(themePath, true);
|
||||
const alias = await themeAlias(themePath, true);
|
||||
// Testing entries, because order matters!
|
||||
expect(Object.entries(alias)).toEqual(
|
||||
Object.entries({
|
||||
|
@ -83,10 +83,10 @@ describe('themeAlias', () => {
|
|||
expect(alias).not.toEqual({});
|
||||
});
|
||||
|
||||
test('valid themePath 2 with components without original', () => {
|
||||
test('valid themePath 2 with components without original', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'theme-2');
|
||||
const alias = themeAlias(themePath, false);
|
||||
const alias = await themeAlias(themePath, false);
|
||||
// Testing entries, because order matters!
|
||||
expect(Object.entries(alias)).toEqual(
|
||||
Object.entries({
|
||||
|
@ -107,26 +107,26 @@ describe('themeAlias', () => {
|
|||
expect(alias).not.toEqual({});
|
||||
});
|
||||
|
||||
test('valid themePath with no components', () => {
|
||||
test('valid themePath with no components', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'empty-theme');
|
||||
fs.ensureDirSync(themePath);
|
||||
const alias = themeAlias(themePath, true);
|
||||
await fs.ensureDir(themePath);
|
||||
const alias = await themeAlias(themePath, true);
|
||||
expect(alias).toEqual({});
|
||||
});
|
||||
|
||||
test('valid themePath with no components without original', () => {
|
||||
test('valid themePath with no components without original', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, 'empty-theme');
|
||||
fs.ensureDirSync(themePath);
|
||||
const alias = themeAlias(themePath, false);
|
||||
await fs.ensureDir(themePath);
|
||||
const alias = await themeAlias(themePath, false);
|
||||
expect(alias).toEqual({});
|
||||
});
|
||||
|
||||
test('invalid themePath that does not exist', () => {
|
||||
test('invalid themePath that does not exist', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const themePath = path.join(fixtures, '__noExist__');
|
||||
const alias = themeAlias(themePath, true);
|
||||
const alias = await themeAlias(themePath, true);
|
||||
expect(alias).toEqual({});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,12 +9,12 @@ import path from 'path';
|
|||
import {loadThemeAliases} from '../index';
|
||||
|
||||
describe('loadThemeAliases', () => {
|
||||
test('next alias can override the previous alias', () => {
|
||||
test('next alias can override the previous alias', async () => {
|
||||
const fixtures = path.join(__dirname, '__fixtures__');
|
||||
const theme1Path = path.join(fixtures, 'theme-1');
|
||||
const theme2Path = path.join(fixtures, 'theme-2');
|
||||
|
||||
const alias = loadThemeAliases([theme1Path, theme2Path], []);
|
||||
const alias = await loadThemeAliases([theme1Path, theme2Path], []);
|
||||
|
||||
// Testing entries, because order matters!
|
||||
expect(Object.entries(alias)).toEqual(
|
||||
|
|
|
@ -25,16 +25,15 @@ export function sortAliases(aliases: ThemeAliases): ThemeAliases {
|
|||
return Object.fromEntries(entries);
|
||||
}
|
||||
|
||||
// TODO make async
|
||||
export default function themeAlias(
|
||||
export default async function themeAlias(
|
||||
themePath: string,
|
||||
addOriginalAlias: boolean,
|
||||
): ThemeAliases {
|
||||
if (!fs.pathExistsSync(themePath)) {
|
||||
): Promise<ThemeAliases> {
|
||||
if (!(await fs.pathExists(themePath))) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const themeComponentFiles = Globby.sync(['**/*.{js,jsx,ts,tsx}'], {
|
||||
const themeComponentFiles = await Globby(['**/*.{js,jsx,ts,tsx}'], {
|
||||
cwd: themePath,
|
||||
});
|
||||
|
||||
|
|
|
@ -12,14 +12,14 @@ import themeAlias, {sortAliases} from './alias';
|
|||
|
||||
const ThemeFallbackDir = path.resolve(__dirname, '../../client/theme-fallback');
|
||||
|
||||
export function loadThemeAliases(
|
||||
export async function loadThemeAliases(
|
||||
themePaths: string[],
|
||||
userThemePaths: string[],
|
||||
): ThemeAliases {
|
||||
): Promise<ThemeAliases> {
|
||||
const aliases: ThemeAliases = {};
|
||||
|
||||
themePaths.forEach((themePath) => {
|
||||
const themeAliases = themeAlias(themePath, true);
|
||||
for (const themePath of themePaths) {
|
||||
const themeAliases = await themeAlias(themePath, true);
|
||||
Object.keys(themeAliases).forEach((aliasKey) => {
|
||||
// If this alias shadows a previous one, use @theme-init to preserve the
|
||||
// initial one. @theme-init is only applied once: to the initial theme
|
||||
|
@ -33,12 +33,12 @@ export function loadThemeAliases(
|
|||
}
|
||||
aliases[aliasKey] = themeAliases[aliasKey];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
userThemePaths.forEach((themePath) => {
|
||||
const userThemeAliases = themeAlias(themePath, false);
|
||||
for (const themePath of userThemePaths) {
|
||||
const userThemeAliases = await themeAlias(themePath, false);
|
||||
Object.assign(aliases, userThemeAliases);
|
||||
});
|
||||
}
|
||||
|
||||
return sortAliases(aliases);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export function loadPluginsThemeAliases({
|
|||
}: {
|
||||
siteDir: string;
|
||||
plugins: LoadedPlugin[];
|
||||
}): ThemeAliases {
|
||||
}): Promise<ThemeAliases> {
|
||||
const pluginThemes: string[] = plugins
|
||||
.map((plugin) => (plugin.getThemePath ? plugin.getThemePath() : undefined))
|
||||
.filter((x): x is string => Boolean(x));
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import type {RouteConfig} from '@docusaurus/types';
|
||||
import nodePath from 'path';
|
||||
import path from 'path';
|
||||
import {posixPath, Globby} from '@docusaurus/utils';
|
||||
|
||||
// Recursively get the final routes (routes with no subroutes)
|
||||
|
@ -26,7 +26,7 @@ export async function safeGlobby(
|
|||
// Required for Windows support, as paths using \ should not be used by globby
|
||||
// (also using the windows hard drive prefix like c: is not a good idea)
|
||||
const globPaths = patterns.map((dirPath) =>
|
||||
posixPath(nodePath.relative(process.cwd(), dirPath)),
|
||||
posixPath(path.relative(process.cwd(), dirPath)),
|
||||
);
|
||||
|
||||
return Globby(globPaths, options);
|
||||
|
|
|
@ -9,27 +9,27 @@ import {getPluginVersion} from '..';
|
|||
import path from 'path';
|
||||
|
||||
describe('getPluginVersion', () => {
|
||||
it('Can detect external packages plugins versions of correctly.', () => {
|
||||
expect(
|
||||
it('Can detect external packages plugins versions of correctly.', async () => {
|
||||
await expect(
|
||||
getPluginVersion(
|
||||
path.join(__dirname, '..', '__fixtures__', 'dummy-plugin.js'),
|
||||
// Make the plugin appear external.
|
||||
path.join(__dirname, '..', '..', '..', '..', '..', '..', 'website'),
|
||||
),
|
||||
).toEqual({type: 'package', version: 'random-version'});
|
||||
).resolves.toEqual({type: 'package', version: 'random-version'});
|
||||
});
|
||||
|
||||
it('Can detect project plugins versions correctly.', () => {
|
||||
expect(
|
||||
it('Can detect project plugins versions correctly.', async () => {
|
||||
await expect(
|
||||
getPluginVersion(
|
||||
path.join(__dirname, '..', '__fixtures__', 'dummy-plugin.js'),
|
||||
// Make the plugin appear project local.
|
||||
path.join(__dirname, '..', '__fixtures__'),
|
||||
),
|
||||
).toEqual({type: 'project'});
|
||||
).resolves.toEqual({type: 'project'});
|
||||
});
|
||||
|
||||
it('Can detect local packages versions correctly.', () => {
|
||||
expect(getPluginVersion('/', '/')).toEqual({type: 'local'});
|
||||
it('Can detect local packages versions correctly.', async () => {
|
||||
await expect(getPluginVersion('/', '/')).resolves.toEqual({type: 'local'});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
*/
|
||||
|
||||
import type {DocusaurusPluginVersionInformation} from '@docusaurus/types';
|
||||
import {existsSync, lstatSync} from 'fs-extra';
|
||||
import {dirname, join} from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
export function getPackageJsonVersion(
|
||||
export async function getPackageJsonVersion(
|
||||
packageJsonPath: string,
|
||||
): string | undefined {
|
||||
if (existsSync(packageJsonPath)) {
|
||||
): Promise<string | undefined> {
|
||||
if (await fs.pathExists(packageJsonPath)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require
|
||||
const {version} = require(packageJsonPath);
|
||||
return typeof version === 'string' ? version : undefined;
|
||||
|
@ -20,10 +20,10 @@ export function getPackageJsonVersion(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function getPackageJsonName(
|
||||
export async function getPackageJsonName(
|
||||
packageJsonPath: string,
|
||||
): string | undefined {
|
||||
if (existsSync(packageJsonPath)) {
|
||||
): Promise<string | undefined> {
|
||||
if (await fs.pathExists(packageJsonPath)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-dynamic-require, global-require
|
||||
const {name} = require(packageJsonPath);
|
||||
return typeof name === 'string' ? name : undefined;
|
||||
|
@ -31,17 +31,20 @@ export function getPackageJsonName(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function getPluginVersion(
|
||||
export async function getPluginVersion(
|
||||
pluginPath: string,
|
||||
siteDir: string,
|
||||
): DocusaurusPluginVersionInformation {
|
||||
let potentialPluginPackageJsonDirectory = dirname(pluginPath);
|
||||
): Promise<DocusaurusPluginVersionInformation> {
|
||||
let potentialPluginPackageJsonDirectory = path.dirname(pluginPath);
|
||||
while (potentialPluginPackageJsonDirectory !== '/') {
|
||||
const packageJsonPath = join(
|
||||
const packageJsonPath = path.join(
|
||||
potentialPluginPackageJsonDirectory,
|
||||
'package.json',
|
||||
);
|
||||
if (existsSync(packageJsonPath) && lstatSync(packageJsonPath).isFile()) {
|
||||
if (
|
||||
(await fs.pathExists(packageJsonPath)) &&
|
||||
(await fs.lstat(packageJsonPath)).isFile()
|
||||
) {
|
||||
if (potentialPluginPackageJsonDirectory === siteDir) {
|
||||
// If the plugin belongs to the same docusaurus project, we classify it
|
||||
// as local plugin.
|
||||
|
@ -49,11 +52,11 @@ export function getPluginVersion(
|
|||
}
|
||||
return {
|
||||
type: 'package',
|
||||
name: getPackageJsonName(packageJsonPath),
|
||||
version: getPackageJsonVersion(packageJsonPath),
|
||||
name: await getPackageJsonName(packageJsonPath),
|
||||
version: await getPackageJsonVersion(packageJsonPath),
|
||||
};
|
||||
}
|
||||
potentialPluginPackageJsonDirectory = dirname(
|
||||
potentialPluginPackageJsonDirectory = path.dirname(
|
||||
potentialPluginPackageJsonDirectory,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -68,10 +68,10 @@ describe('babel transpilation exclude logic', () => {
|
|||
});
|
||||
|
||||
describe('getDocusaurusAliases()', () => {
|
||||
test('return appropriate webpack aliases', () => {
|
||||
test('return appropriate webpack aliases', async () => {
|
||||
// using relative paths makes tests work everywhere
|
||||
const relativeDocusaurusAliases = _.mapValues(
|
||||
getDocusaurusAliases(),
|
||||
await getDocusaurusAliases(),
|
||||
(aliasValue) => posixPath(path.relative(__dirname, aliasValue)),
|
||||
);
|
||||
expect(relativeDocusaurusAliases).toMatchSnapshot();
|
||||
|
@ -120,10 +120,10 @@ describe('base webpack config', () => {
|
|||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
test('should create webpack aliases', () => {
|
||||
test('should create webpack aliases', async () => {
|
||||
// @ts-expect-error: Docusaurus webpack alias is always an object
|
||||
const aliases: ThemeAliases =
|
||||
createBaseConfig(props, true).resolve?.alias ?? {};
|
||||
(await createBaseConfig(props, true)).resolve?.alias ?? {};
|
||||
// Make aliases relative so that test work on all computers
|
||||
const relativeAliases = _.mapValues(aliases, (a) =>
|
||||
posixPath(path.relative(props.siteDir, a)),
|
||||
|
@ -131,14 +131,14 @@ describe('base webpack config', () => {
|
|||
expect(relativeAliases).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should use svg rule', () => {
|
||||
test('should use svg rule', async () => {
|
||||
const fileLoaderUtils = utils.getFileLoaderUtils();
|
||||
const mockSvg = jest.spyOn(fileLoaderUtils.rules, 'svg');
|
||||
jest
|
||||
.spyOn(utils, 'getFileLoaderUtils')
|
||||
.mockImplementation(() => fileLoaderUtils);
|
||||
|
||||
createBaseConfig(props, false, false);
|
||||
await createBaseConfig(props, false, false);
|
||||
expect(mockSvg).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('webpack dev config', () => {
|
|||
test('simple', async () => {
|
||||
console.log = jest.fn();
|
||||
const props = await loadSetup('simple');
|
||||
const config = createClientConfig(props);
|
||||
const config = await createClientConfig(props);
|
||||
const errors = validate(config);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
@ -22,7 +22,7 @@ describe('webpack dev config', () => {
|
|||
test('custom', async () => {
|
||||
console.log = jest.fn();
|
||||
const props = await loadSetup('custom');
|
||||
const config = createClientConfig(props);
|
||||
const config = await createClientConfig(props);
|
||||
const errors = validate(config);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ describe('webpack production config', () => {
|
|||
test('simple', async () => {
|
||||
console.log = jest.fn();
|
||||
const props = await loadSetup('simple');
|
||||
const config = createServerConfig({props});
|
||||
const config = await createServerConfig({props});
|
||||
const errors = validate(config);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
@ -22,7 +22,7 @@ describe('webpack production config', () => {
|
|||
test('custom', async () => {
|
||||
console.log = jest.fn();
|
||||
const props = await loadSetup('custom');
|
||||
const config = createServerConfig({props});
|
||||
const config = await createServerConfig({props});
|
||||
const errors = validate(config);
|
||||
expect(errors).toBeUndefined();
|
||||
});
|
||||
|
|
|
@ -44,13 +44,13 @@ export function excludeJS(modulePath: string): boolean {
|
|||
);
|
||||
}
|
||||
|
||||
export function getDocusaurusAliases(): Record<string, string> {
|
||||
export async function getDocusaurusAliases(): Promise<Record<string, string>> {
|
||||
const dirPath = path.resolve(__dirname, '../client/exports');
|
||||
const extensions = ['.js', '.ts', '.tsx'];
|
||||
|
||||
const aliases: Record<string, string> = {};
|
||||
|
||||
fs.readdirSync(dirPath)
|
||||
(await fs.readdir(dirPath))
|
||||
.filter((fileName) => extensions.includes(path.extname(fileName)))
|
||||
.forEach((fileName) => {
|
||||
const fileNameWithoutExtension = path.basename(
|
||||
|
@ -64,11 +64,11 @@ export function getDocusaurusAliases(): Record<string, string> {
|
|||
return aliases;
|
||||
}
|
||||
|
||||
export function createBaseConfig(
|
||||
export async function createBaseConfig(
|
||||
props: Props,
|
||||
isServer: boolean,
|
||||
minify: boolean = true,
|
||||
): Configuration {
|
||||
): Promise<Configuration> {
|
||||
const {
|
||||
outDir,
|
||||
siteDir,
|
||||
|
@ -90,7 +90,7 @@ export function createBaseConfig(
|
|||
const name = isServer ? 'server' : 'client';
|
||||
const mode = isProd ? 'production' : 'development';
|
||||
|
||||
const themeAliases = loadPluginsThemeAliases({siteDir, plugins});
|
||||
const themeAliases = await loadPluginsThemeAliases({siteDir, plugins});
|
||||
|
||||
return {
|
||||
mode,
|
||||
|
@ -158,7 +158,7 @@ export function createBaseConfig(
|
|||
// Note: a @docusaurus alias would also catch @docusaurus/theme-common,
|
||||
// so we use fine-grained aliases instead
|
||||
// '@docusaurus': path.resolve(__dirname, '../client/exports'),
|
||||
...getDocusaurusAliases(),
|
||||
...(await getDocusaurusAliases()),
|
||||
...themeAliases,
|
||||
},
|
||||
// This allows you to set a fallback for where Webpack should look for
|
||||
|
@ -169,7 +169,7 @@ export function createBaseConfig(
|
|||
modules: [
|
||||
path.resolve(__dirname, '..', '..', 'node_modules'),
|
||||
'node_modules',
|
||||
path.resolve(fs.realpathSync(process.cwd()), 'node_modules'),
|
||||
path.resolve(await fs.realpath(process.cwd()), 'node_modules'),
|
||||
],
|
||||
},
|
||||
resolveLoader: {
|
||||
|
@ -225,7 +225,7 @@ export function createBaseConfig(
|
|||
use: [
|
||||
getCustomizableJSLoader(siteConfig.webpack?.jsLoader)({
|
||||
isServer,
|
||||
babelOptions: getCustomBabelConfigFilePath(siteDir),
|
||||
babelOptions: await getCustomBabelConfigFilePath(siteDir),
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
|
|
@ -15,12 +15,12 @@ import {createBaseConfig} from './base';
|
|||
import ChunkAssetPlugin from './plugins/ChunkAssetPlugin';
|
||||
import LogPlugin from './plugins/LogPlugin';
|
||||
|
||||
export default function createClientConfig(
|
||||
export default async function createClientConfig(
|
||||
props: Props,
|
||||
minify: boolean = true,
|
||||
): Configuration {
|
||||
): Promise<Configuration> {
|
||||
const isBuilding = process.argv[2] === 'build';
|
||||
const config = createBaseConfig(props, false, minify);
|
||||
const config = await createBaseConfig(props, false, minify);
|
||||
|
||||
const clientConfig = merge(config, {
|
||||
// useless, disabled on purpose (errors on existing sites with no
|
||||
|
|
|
@ -18,13 +18,13 @@ import {NODE_MAJOR_VERSION, NODE_MINOR_VERSION} from '@docusaurus/utils';
|
|||
// Forked for Docusaurus: https://github.com/slorber/static-site-generator-webpack-plugin
|
||||
import StaticSiteGeneratorPlugin from '@slorber/static-site-generator-webpack-plugin';
|
||||
|
||||
export default function createServerConfig({
|
||||
export default async function createServerConfig({
|
||||
props,
|
||||
onLinksCollected = () => {},
|
||||
}: {
|
||||
props: Props;
|
||||
onLinksCollected?: (staticPagePath: string, links: string[]) => void;
|
||||
}): Configuration {
|
||||
}): Promise<Configuration> {
|
||||
const {
|
||||
baseUrl,
|
||||
routesPaths,
|
||||
|
@ -35,7 +35,7 @@ export default function createServerConfig({
|
|||
ssrTemplate,
|
||||
siteConfig: {noIndex, trailingSlash},
|
||||
} = props;
|
||||
const config = createBaseConfig(props, true);
|
||||
const config = await createBaseConfig(props, true);
|
||||
|
||||
const routesLocation: Record<string, string> = {};
|
||||
// Array of paths to be rendered. Relative to output directory
|
||||
|
|
|
@ -101,14 +101,14 @@ export function getStyleLoaders(
|
|||
];
|
||||
}
|
||||
|
||||
export function getCustomBabelConfigFilePath(
|
||||
export async function getCustomBabelConfigFilePath(
|
||||
siteDir: string,
|
||||
): string | undefined {
|
||||
): Promise<string | undefined> {
|
||||
const customBabelConfigurationPath = path.join(
|
||||
siteDir,
|
||||
BABEL_CONFIG_FILE_NAME,
|
||||
);
|
||||
return fs.existsSync(customBabelConfigurationPath)
|
||||
return (await fs.pathExists(customBabelConfigurationPath))
|
||||
? customBabelConfigurationPath
|
||||
: undefined;
|
||||
}
|
||||
|
@ -333,19 +333,21 @@ ${err}`,
|
|||
}
|
||||
|
||||
// Read file and throw an error if it doesn't exist
|
||||
function readEnvFile(file: string, type: string) {
|
||||
if (!fs.existsSync(file)) {
|
||||
async function readEnvFile(file: string, type: string) {
|
||||
if (!(await fs.pathExists(file))) {
|
||||
throw new Error(
|
||||
`You specified ${type} in your env, but the file "${file}" can't be found.`,
|
||||
);
|
||||
}
|
||||
return fs.readFileSync(file);
|
||||
return fs.readFile(file);
|
||||
}
|
||||
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
// Get the https config
|
||||
// Return cert files if provided in env, otherwise just true or false
|
||||
export function getHttpsConfig(): boolean | {cert: Buffer; key: Buffer} {
|
||||
export async function getHttpsConfig(): Promise<
|
||||
boolean | {cert: Buffer; key: Buffer}
|
||||
> {
|
||||
const appDirectory = await fs.realpath(process.cwd());
|
||||
const {SSL_CRT_FILE, SSL_KEY_FILE, HTTPS} = process.env;
|
||||
const isHttps = HTTPS === 'true';
|
||||
|
||||
|
@ -353,8 +355,8 @@ export function getHttpsConfig(): boolean | {cert: Buffer; key: Buffer} {
|
|||
const crtFile = path.resolve(appDirectory, SSL_CRT_FILE);
|
||||
const keyFile = path.resolve(appDirectory, SSL_KEY_FILE);
|
||||
const config = {
|
||||
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
||||
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
||||
cert: await readEnvFile(crtFile, 'SSL_CRT_FILE'),
|
||||
key: await readEnvFile(keyFile, 'SSL_KEY_FILE'),
|
||||
};
|
||||
|
||||
validateKeyAndCerts({...config, keyFile, crtFile});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue