mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-02 08:19:07 +02:00
perf(v2): skip runtime fileHash cache in prod & get timestamp asynchronously (#1951)
* skip hash calculation in prod when generating file * perf: convert lastUpdated to be async process * changelog
This commit is contained in:
parent
e04c8f140f
commit
639d8d3eac
8 changed files with 107 additions and 42 deletions
|
@ -16,7 +16,7 @@
|
|||
"dependencies": {
|
||||
"@docusaurus/mdx-loader": "^2.0.0-alpha.33",
|
||||
"@docusaurus/utils": "^2.0.0-alpha.33",
|
||||
"cross-spawn": "^7.0.1",
|
||||
"execa": "^3.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"globby": "^10.0.1",
|
||||
"import-fresh": "^3.1.0",
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import shell from 'shelljs';
|
||||
import spawn from 'cross-spawn';
|
||||
|
||||
import lastUpdate from '../lastUpdate';
|
||||
|
||||
|
@ -17,8 +16,8 @@ describe('lastUpdate', () => {
|
|||
__dirname,
|
||||
'__fixtures__/simple-site/docs/hello.md',
|
||||
);
|
||||
test('existing test file in repository with Git timestamp', () => {
|
||||
const lastUpdateData = lastUpdate(existingFilePath);
|
||||
test('existing test file in repository with Git timestamp', async () => {
|
||||
const lastUpdateData = await lastUpdate(existingFilePath);
|
||||
expect(lastUpdateData).not.toBeNull();
|
||||
|
||||
const {author, timestamp} = lastUpdateData;
|
||||
|
@ -29,28 +28,37 @@ describe('lastUpdate', () => {
|
|||
expect(typeof timestamp).toBe('number');
|
||||
});
|
||||
|
||||
test('non-existing file', () => {
|
||||
test('non-existing file', async () => {
|
||||
const consoleMock = jest.spyOn(console, 'error');
|
||||
consoleMock.mockImplementation();
|
||||
const nonExistingFilePath = path.join(
|
||||
__dirname,
|
||||
'__fixtures__',
|
||||
'.nonExisting',
|
||||
);
|
||||
expect(lastUpdate(null)).toBeNull();
|
||||
expect(lastUpdate(undefined)).toBeNull();
|
||||
expect(lastUpdate(nonExistingFilePath)).toBeNull();
|
||||
expect(await lastUpdate(nonExistingFilePath)).toBeNull();
|
||||
expect(consoleMock).toHaveBeenCalledTimes(1);
|
||||
expect(consoleMock).toHaveBeenCalledWith(
|
||||
new Error(
|
||||
`Command failed with exit code 128: git log -1 --format=%ct, %an ${nonExistingFilePath}`,
|
||||
),
|
||||
);
|
||||
expect(await lastUpdate(null)).toBeNull();
|
||||
expect(await lastUpdate(undefined)).toBeNull();
|
||||
consoleMock.mockRestore();
|
||||
});
|
||||
|
||||
test('temporary created file that has no git timestamp', () => {
|
||||
test('temporary created file that has no git timestamp', async () => {
|
||||
const tempFilePath = path.join(__dirname, '__fixtures__', '.temp');
|
||||
fs.writeFileSync(tempFilePath, 'Lorem ipsum :)');
|
||||
expect(lastUpdate(tempFilePath)).toBeNull();
|
||||
expect(await lastUpdate(tempFilePath)).toBeNull();
|
||||
fs.unlinkSync(tempFilePath);
|
||||
});
|
||||
|
||||
test('Git does not exist', () => {
|
||||
test('Git does not exist', async () => {
|
||||
const mock = jest.spyOn(shell, 'which').mockImplementationOnce(() => null);
|
||||
const consoleMock = jest.spyOn(console, 'warn').mockImplementation();
|
||||
const lastUpdateData = lastUpdate(existingFilePath);
|
||||
const lastUpdateData = await lastUpdate(existingFilePath);
|
||||
expect(lastUpdateData).toBeNull();
|
||||
expect(consoleMock).toHaveBeenLastCalledWith(
|
||||
'Sorry, the docs plugin last update options require Git.',
|
||||
|
@ -59,17 +67,4 @@ describe('lastUpdate', () => {
|
|||
consoleMock.mockRestore();
|
||||
mock.mockRestore();
|
||||
});
|
||||
|
||||
test('Error', () => {
|
||||
const mock = jest.spyOn(spawn, 'sync').mockImplementationOnce(() => {
|
||||
throw new Error('PERMISSION Error');
|
||||
});
|
||||
const consoleMock = jest.spyOn(console, 'error').mockImplementation();
|
||||
const lastUpdateData = lastUpdate('/fake/path/');
|
||||
expect(lastUpdateData).toBeNull();
|
||||
expect(consoleMock).toHaveBeenLastCalledWith(new Error('PERMISSION Error'));
|
||||
|
||||
consoleMock.mockRestore();
|
||||
mock.mockRestore();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
|
||||
import shell from 'shelljs';
|
||||
import spawn from 'cross-spawn';
|
||||
import execa from 'execa';
|
||||
|
||||
type FileLastUpdateData = {timestamp?: number; author?: string};
|
||||
|
||||
|
@ -14,9 +14,12 @@ const GIT_COMMIT_TIMESTAMP_AUTHOR_REGEX = /^(\d+), (.+)$/;
|
|||
|
||||
let showedGitRequirementError = false;
|
||||
|
||||
export default function getFileLastUpdate(
|
||||
filePath: string,
|
||||
): FileLastUpdateData | null {
|
||||
export default async function getFileLastUpdate(
|
||||
filePath?: string,
|
||||
): Promise<FileLastUpdateData | null> {
|
||||
if (!filePath) {
|
||||
return null;
|
||||
}
|
||||
function getTimestampAndAuthor(str: string): FileLastUpdateData | null {
|
||||
if (!str) {
|
||||
return null;
|
||||
|
@ -39,12 +42,13 @@ export default function getFileLastUpdate(
|
|||
return null;
|
||||
}
|
||||
|
||||
const result = spawn
|
||||
.sync('git', ['log', '-1', '--format=%ct, %an', filePath])
|
||||
.stdout.toString()
|
||||
.trim();
|
||||
|
||||
return getTimestampAndAuthor(result);
|
||||
const {stdout} = await execa('git', [
|
||||
'log',
|
||||
'-1',
|
||||
'--format=%ct, %an',
|
||||
filePath,
|
||||
]);
|
||||
return getTimestampAndAuthor(stdout);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ export default async function processMetadata({
|
|||
// Use fake data in dev for faster development
|
||||
const fileLastUpdateData =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? lastUpdate(filePath)
|
||||
? await lastUpdate(filePath)
|
||||
: {
|
||||
author: 'Author',
|
||||
timestamp: '1539502055',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue