mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-01 02:12:36 +02:00
refactor(v2): convert @docusaurus/plugin-content-blog
to TypeScript (#1785)
* convert `@docusaurus/plugin-content-blog` to typescript remove divided plugin convert `@docusaurus/plugin-content-blog` to typescript convert `@docusaurus/plugin-content-blog` to typescript convert `@docusaurus/plugin-content-blog` to typescript add `packages/docusaurus-plugin-content-blog/lib` to ignores linted refactoring type definition fix test fails lint * lint
This commit is contained in:
parent
0584407257
commit
78159f6dd5
13 changed files with 253 additions and 43 deletions
|
@ -13,4 +13,4 @@ packages/docusaurus-1.x/lib/core/__tests__/split-tab.test.js
|
|||
packages/docusaurus-utils/lib/
|
||||
packages/docusaurus/lib/
|
||||
packages/docusaurus-init/lib/
|
||||
|
||||
packages/docusaurus-plugin-content-blog/lib/
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,5 +15,4 @@ types
|
|||
packages/docusaurus-utils/lib/
|
||||
packages/docusaurus/lib/
|
||||
packages/docusaurus-init/lib/
|
||||
|
||||
|
||||
packages/docusaurus-plugin-content-blog/lib/
|
||||
|
|
|
@ -5,3 +5,4 @@ build
|
|||
packages/docusaurus-utils/lib/
|
||||
packages/docusaurus/lib/
|
||||
packages/docusaurus-init/lib/
|
||||
packages/docusaurus-plugin-content-blog/lib/
|
||||
|
|
|
@ -17,6 +17,7 @@ module.exports = {
|
|||
'__fixtures__',
|
||||
'/packages/docusaurus/lib',
|
||||
'/packages/docusaurus-utils/lib',
|
||||
'/packages/docusaurus-plugin-content-blog/lib',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.[jt]sx?$': 'babel-jest',
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
"name": "@docusaurus/plugin-content-blog",
|
||||
"version": "2.0.0-alpha.24",
|
||||
"description": "Blog plugin for Docusaurus",
|
||||
"main": "src/index.js",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"tsc": "tsc"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import pluginContentBlog from '../index';
|
||||
import {DocusaurusConfig} from '../typesDocusaurus';
|
||||
|
||||
describe('loadBlog', () => {
|
||||
test('simple website', async () => {
|
||||
const siteDir = path.join(__dirname, '__fixtures__', 'website');
|
||||
const siteConfig = {
|
||||
const siteConfig: DocusaurusConfig = {
|
||||
title: 'Hello',
|
||||
baseUrl: '/',
|
||||
url: 'https://docusaurus.io',
|
|
@ -4,25 +4,42 @@
|
|||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
import fs from 'fs-extra';
|
||||
import globby from 'globby';
|
||||
import _ from 'lodash';
|
||||
import path from 'path';
|
||||
import {parse, normalizeUrl, docuHash} from '@docusaurus/utils';
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const globby = require('globby');
|
||||
const _ = require('lodash');
|
||||
const path = require('path');
|
||||
const {parse, normalizeUrl, docuHash} = require('@docusaurus/utils');
|
||||
import {
|
||||
DateLink,
|
||||
PluginOptions,
|
||||
BlogTags,
|
||||
BlogPost,
|
||||
Tag,
|
||||
BlogContent,
|
||||
BlogItemsToModules,
|
||||
TagsModule,
|
||||
ConfigureWebpackUtils,
|
||||
} from './types';
|
||||
import {
|
||||
LoadContext,
|
||||
PluginContentLoadedActions,
|
||||
RouteModule,
|
||||
} from './typesDocusaurus';
|
||||
import {Configuration} from 'webpack';
|
||||
|
||||
// YYYY-MM-DD-{name}.mdx?
|
||||
// prefer named capture, but old node version do not support
|
||||
const FILENAME_PATTERN = /^(\d{4}-\d{1,2}-\d{1,2})-?(.*?).mdx?$/;
|
||||
|
||||
function toUrl({date, link}) {
|
||||
function toUrl({date, link}: DateLink) {
|
||||
return `${date
|
||||
.toISOString()
|
||||
.substring(0, '2019-01-01'.length)
|
||||
.replace(/-/g, '/')}/${link}`;
|
||||
}
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
const DEFAULT_OPTIONS: PluginOptions = {
|
||||
path: 'blog', // Path to data on filesystem, relative to site dir.
|
||||
routeBasePath: 'blog', // URL Route.
|
||||
include: ['*.md', '*.mdx'], // Extensions to include.
|
||||
|
@ -36,7 +53,10 @@ const DEFAULT_OPTIONS = {
|
|||
truncateMarker: /<!--\s*(truncate)\s*-->/, // string or regex
|
||||
};
|
||||
|
||||
module.exports = function(context, opts) {
|
||||
export default function pluginContentBlog(
|
||||
context: LoadContext,
|
||||
opts: Partial<PluginOptions>,
|
||||
) {
|
||||
const options = {...DEFAULT_OPTIONS, ...opts};
|
||||
const contentPath = path.resolve(context.siteDir, options.path);
|
||||
|
||||
|
@ -64,10 +84,10 @@ module.exports = function(context, opts) {
|
|||
cwd: blogDir,
|
||||
});
|
||||
|
||||
const blogPosts = [];
|
||||
const blogPosts: BlogPost[] = [];
|
||||
|
||||
await Promise.all(
|
||||
blogFiles.map(async relativeSource => {
|
||||
blogFiles.map(async (relativeSource: string) => {
|
||||
// Cannot use path.join() as it resolves '../' and removes the '@site'. Let webpack loader resolve it.
|
||||
const source = path.join(blogDir, relativeSource);
|
||||
const aliasedSource = `@site/${path.relative(siteDir, source)}`;
|
||||
|
@ -110,7 +130,9 @@ module.exports = function(context, opts) {
|
|||
});
|
||||
}),
|
||||
);
|
||||
blogPosts.sort((a, b) => b.metadata.date - a.metadata.date);
|
||||
blogPosts.sort(
|
||||
(a, b) => b.metadata.date.getTime() - a.metadata.date.getTime(),
|
||||
);
|
||||
|
||||
// Blog pagination routes.
|
||||
// Example: `/blog`, `/blog/page/1`, `/blog/page/2`
|
||||
|
@ -120,7 +142,7 @@ module.exports = function(context, opts) {
|
|||
|
||||
const blogListPaginated = [];
|
||||
|
||||
function blogPaginationPermalink(page) {
|
||||
function blogPaginationPermalink(page: number) {
|
||||
return page > 0
|
||||
? normalizeUrl([basePageUrl, `page/${page + 1}`])
|
||||
: basePageUrl;
|
||||
|
@ -146,7 +168,7 @@ module.exports = function(context, opts) {
|
|||
});
|
||||
}
|
||||
|
||||
const blogTags = {};
|
||||
const blogTags: BlogTags = {};
|
||||
const tagsPath = normalizeUrl([basePageUrl, 'tags']);
|
||||
blogPosts.forEach(blogPost => {
|
||||
const {tags} = blogPost.metadata;
|
||||
|
@ -159,6 +181,7 @@ module.exports = function(context, opts) {
|
|||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
blogPost.metadata.tags = tags.map(tag => {
|
||||
if (typeof tag === 'string') {
|
||||
const normalizedTag = _.kebabCase(tag);
|
||||
const permalink = normalizeUrl([tagsPath, normalizedTag]);
|
||||
if (!blogTags[normalizedTag]) {
|
||||
|
@ -174,7 +197,10 @@ module.exports = function(context, opts) {
|
|||
return {
|
||||
label: tag,
|
||||
permalink,
|
||||
};
|
||||
} as Tag;
|
||||
} else {
|
||||
return tag;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -189,7 +215,13 @@ module.exports = function(context, opts) {
|
|||
};
|
||||
},
|
||||
|
||||
async contentLoaded({content: blogContents, actions}) {
|
||||
async contentLoaded({
|
||||
content: blogContents,
|
||||
actions,
|
||||
}: {
|
||||
content: BlogContent;
|
||||
actions: PluginContentLoadedActions;
|
||||
}) {
|
||||
if (!blogContents) {
|
||||
return;
|
||||
}
|
||||
|
@ -209,7 +241,7 @@ module.exports = function(context, opts) {
|
|||
blogTagsListPath,
|
||||
} = blogContents;
|
||||
|
||||
const blogItemsToModules = {};
|
||||
const blogItemsToModules: BlogItemsToModules = {};
|
||||
// Create routes for blog entries.
|
||||
const blogItems = await Promise.all(
|
||||
blogPosts.map(async blogPost => {
|
||||
|
@ -245,7 +277,7 @@ module.exports = function(context, opts) {
|
|||
metadata: metadataPath,
|
||||
prevItem: prevItem && prevItem.metadataPath,
|
||||
nextItem: nextItem && nextItem.metadataPath,
|
||||
},
|
||||
} as RouteModule,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -288,7 +320,7 @@ module.exports = function(context, opts) {
|
|||
);
|
||||
|
||||
// Tags.
|
||||
const tagsModule = {};
|
||||
const tagsModule: TagsModule = {};
|
||||
|
||||
await Promise.all(
|
||||
Object.keys(blogTags).map(async tag => {
|
||||
|
@ -352,7 +384,11 @@ module.exports = function(context, opts) {
|
|||
}
|
||||
},
|
||||
|
||||
configureWebpack(config, isServer, {getBabelLoader, getCacheLoader}) {
|
||||
configureWebpack(
|
||||
_config: Configuration,
|
||||
isServer: boolean,
|
||||
{getBabelLoader, getCacheLoader}: ConfigureWebpackUtils,
|
||||
) {
|
||||
const {rehypePlugins, remarkPlugins, truncateMarker} = options;
|
||||
return {
|
||||
module: {
|
||||
|
@ -383,4 +419,4 @@ module.exports = function(context, opts) {
|
|||
};
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
|
@ -6,8 +6,9 @@
|
|||
*/
|
||||
|
||||
const {parseQuery, getOptions} = require('loader-utils');
|
||||
import {loader} from 'webpack';
|
||||
|
||||
module.exports = async function(fileString) {
|
||||
export = function(fileString: string) {
|
||||
const callback = this.async();
|
||||
|
||||
const {truncateMarker} = getOptions(this);
|
||||
|
@ -25,5 +26,5 @@ module.exports = async function(fileString) {
|
|||
// eslint-disable-next-line
|
||||
finalContent = fileString.split(truncateMarker)[0];
|
||||
}
|
||||
return callback(null, finalContent);
|
||||
};
|
||||
return callback && callback(null, finalContent);
|
||||
} as loader.Loader;
|
93
packages/docusaurus-plugin-content-blog/src/types.ts
Normal file
93
packages/docusaurus-plugin-content-blog/src/types.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import {Loader} from 'webpack';
|
||||
|
||||
export interface BlogContent {
|
||||
blogPosts: BlogPost[];
|
||||
blogListPaginated: BlogPaginated[];
|
||||
blogTags: BlogTags;
|
||||
blogTagsListPath: string;
|
||||
}
|
||||
|
||||
export interface DateLink {
|
||||
date: Date;
|
||||
link: string;
|
||||
}
|
||||
|
||||
export interface PluginOptions {
|
||||
path: string;
|
||||
routeBasePath: string;
|
||||
include: string[];
|
||||
postsPerPage: number;
|
||||
blogListComponent: string;
|
||||
blogPostComponent: string;
|
||||
blogTagsListComponent: string;
|
||||
blogTagsPostsComponent: string;
|
||||
remarkPlugins: string[];
|
||||
rehypePlugins: string[];
|
||||
truncateMarker: RegExp | string;
|
||||
}
|
||||
|
||||
export interface BlogTags {
|
||||
[key: string]: BlogTag;
|
||||
}
|
||||
|
||||
export interface BlogTag {
|
||||
name: string;
|
||||
items: string[];
|
||||
permalink: string;
|
||||
}
|
||||
|
||||
export interface BlogPost {
|
||||
id: string;
|
||||
metadata: MetaData;
|
||||
}
|
||||
|
||||
export interface BlogPaginated {
|
||||
metadata: MetaData;
|
||||
items: string[];
|
||||
}
|
||||
|
||||
export interface MetaData {
|
||||
permalink: string;
|
||||
source: string;
|
||||
description: string;
|
||||
date: Date;
|
||||
tags: (Tag | string)[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface Tag {
|
||||
label: string;
|
||||
permalink: string;
|
||||
}
|
||||
|
||||
export interface BlogItemsToModules {
|
||||
[key: string]: MetaDataWithPath;
|
||||
}
|
||||
|
||||
export interface MetaDataWithPath {
|
||||
metadata: MetaData;
|
||||
metadataPath: string;
|
||||
}
|
||||
|
||||
export interface TagsModule {
|
||||
[key: string]: TagModule;
|
||||
}
|
||||
|
||||
export interface TagModule {
|
||||
allTagsPath: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
count: number;
|
||||
permalink: string;
|
||||
}
|
||||
|
||||
export interface ConfigureWebpackUtils {
|
||||
getStyleLoaders: (
|
||||
isServer: boolean,
|
||||
cssOptions: {
|
||||
[key: string]: any;
|
||||
},
|
||||
) => Loader[];
|
||||
getCacheLoader: (isServer: boolean, cacheOptions?: {}) => Loader | null;
|
||||
getBabelLoader: (isServer: boolean, babelOptions?: {}) => Loader;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
import {ParsedUrlQueryInput} from 'querystring';
|
||||
|
||||
export interface DocusaurusConfig {
|
||||
baseUrl: string;
|
||||
favicon?: string;
|
||||
tagline?: string;
|
||||
title: string;
|
||||
url: string;
|
||||
organizationName?: string;
|
||||
projectName?: string;
|
||||
githubHost?: string;
|
||||
plugins?: PluginConfig[];
|
||||
themes?: PluginConfig[];
|
||||
presets?: PresetConfig[];
|
||||
themeConfig?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
customFields?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
export type PluginConfig = [string, Object | undefined] | string;
|
||||
|
||||
export type PresetConfig = [string, Object | undefined] | string;
|
||||
|
||||
export interface CLIOptions {
|
||||
[option: string]: any;
|
||||
}
|
||||
|
||||
export interface LoadContext {
|
||||
siteDir: string;
|
||||
generatedFilesDir?: string;
|
||||
siteConfig: DocusaurusConfig;
|
||||
cliOptions?: CLIOptions;
|
||||
outDir?: string;
|
||||
baseUrl?: string;
|
||||
}
|
||||
|
||||
export interface PluginContentLoadedActions {
|
||||
addRoute(config: RouteConfig): void;
|
||||
createData(name: string, data: Object): Promise<string>;
|
||||
}
|
||||
|
||||
export type Module =
|
||||
| {
|
||||
path: string;
|
||||
__import?: boolean;
|
||||
query?: ParsedUrlQueryInput;
|
||||
}
|
||||
| string;
|
||||
|
||||
export interface RouteModule {
|
||||
[module: string]: Module | RouteModule | RouteModule[];
|
||||
}
|
||||
|
||||
export interface RouteConfig {
|
||||
path: string;
|
||||
component: string;
|
||||
modules?: RouteModule;
|
||||
routes?: RouteConfig[];
|
||||
exact?: boolean;
|
||||
}
|
9
packages/docusaurus-plugin-content-blog/tsconfig.json
Normal file
9
packages/docusaurus-plugin-content-blog/tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||
"rootDir": "src",
|
||||
"outDir": "lib",
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ export async function loadPlugins({
|
|||
|
||||
// module is any valid module identifier - npm package or locally-resolved path.
|
||||
const pluginModule = importFresh(pluginModuleImport);
|
||||
return pluginModule(context, pluginOptions);
|
||||
return (pluginModule.default || pluginModule)(context, pluginOptions);
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
|
@ -30,7 +30,10 @@ export function loadPresets(
|
|||
}
|
||||
|
||||
const presetModule = importFresh(presetModuleImport);
|
||||
const preset: Preset = presetModule(context, presetOptions);
|
||||
const preset: Preset = (presetModule.default || presetModule)(
|
||||
context,
|
||||
presetOptions,
|
||||
);
|
||||
|
||||
preset.plugins && unflatPlugins.push(preset.plugins);
|
||||
preset.themes && unflatThemes.push(preset.themes);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue