Yuki Takei 3 лет назад
Родитель
Сommit
5053a10576

+ 1 - 0
packages/app/next.config.js

@@ -29,6 +29,7 @@ const setupTranspileModules = () => {
     'decode-named-character-reference',
     'hastscript',
     'html-void-elements',
+    'is-absolute-url',
     'longest-streak',
     'property-information',
     'space-separated-tokens',

+ 1 - 0
packages/app/package.json

@@ -115,6 +115,7 @@
     "i18next-chained-backend": "^3.0.2",
     "i18next-http-backend": "^1.4.1",
     "i18next-localstorage-backend": "^3.1.3",
+    "is-absolute-url": "^4.0.1",
     "is-iso-date": "^0.0.1",
     "lucene-query-parser": "^1.2.0",
     "md5": "^2.2.1",

+ 35 - 0
packages/app/src/services/renderer/rehype-plugins/relative-links.ts

@@ -0,0 +1,35 @@
+import { selectAll, HastNode } from 'hast-util-select';
+import isAbsolute from 'is-absolute-url';
+import { Plugin } from 'unified';
+
+type RelativeLinksPluginParams = {
+  pagePath?: string,
+}
+
+export const relativeLinks: Plugin<[RelativeLinksPluginParams]> = (options = {}) => {
+  return (tree) => {
+    if (options.pagePath == null) {
+      return;
+    }
+
+    const pagePath = options.pagePath;
+    const anchors = selectAll('a[href]', tree as HastNode);
+
+    anchors.forEach((anchor) => {
+      if (anchor.properties == null) {
+        return;
+      }
+
+      const href = anchor.properties.href;
+      if (href == null || typeof href !== 'string' || isAbsolute(href)) {
+        return;
+      }
+
+      // generate relative pathname
+      const baseUrl = new URL(pagePath, 'https://example.com');
+      const relativeUrl = new URL(href, baseUrl);
+
+      anchor.properties.href = relativeUrl.pathname;
+    });
+  };
+};

+ 4 - 1
packages/app/src/services/renderer/renderer.ts

@@ -13,9 +13,11 @@ import { CodeBlock } from '~/components/ReactMarkdownComponents/CodeBlock';
 import { Header } from '~/components/ReactMarkdownComponents/Header';
 import { NextLink } from '~/components/ReactMarkdownComponents/NextLink';
 import { RendererConfig } from '~/interfaces/services/renderer';
-import { addClass } from '~/services/renderer/rehype-plugins/add-class';
 import loggerFactory from '~/utils/logger';
 
+import { addClass } from './rehype-plugins/add-class';
+import { relativeLinks } from './rehype-plugins/relative-links';
+
 // import CsvToTable from './PreProcessor/CsvToTable';
 // import EasyGrid from './PreProcessor/EasyGrid';
 // import Linker from './PreProcessor/Linker';
@@ -218,6 +220,7 @@ const generateCommonOptions = (pagePath: string|undefined, config: RendererConfi
     remarkPlugins: [gfm],
     rehypePlugins: [
       slug,
+      [relativeLinks, { pagePath }],
       raw,
       [sanitize, {
         ...sanitizeDefaultSchema,

+ 17 - 4
packages/app/src/stores/renderer.tsx

@@ -9,7 +9,7 @@ import {
 } from '~/services/renderer/renderer';
 
 
-import { useCurrentPageTocNode, useRendererConfig } from './context';
+import { useCurrentPagePath, useCurrentPageTocNode, useRendererConfig } from './context';
 
 interface ReactMarkdownOptionsGenerator {
   (config: RendererConfig): RendererOptions
@@ -38,11 +38,24 @@ const _useOptionsBase = (
 };
 
 export const useViewOptions = (): SWRResponse<RendererOptions, Error> => {
-  const key = 'viewOptions';
-
+  const { data: currentPagePath } = useCurrentPagePath();
+  const { data: rendererConfig } = useRendererConfig();
   const { mutate: storeTocNode } = useCurrentPageTocNode();
 
-  return _useOptionsBase(key, config => generateViewOptions(config, storeTocNode));
+  const isAllDataValid = currentPagePath != null && rendererConfig != null;
+
+  const key = isAllDataValid
+    ? ['viewOptions', currentPagePath, rendererConfig]
+    : null;
+
+  const swrResult = useSWRImmutable<RendererOptions, Error>(key);
+
+  if (isAllDataValid && swrResult.data == null) {
+    swrResult.mutate(generateViewOptions(currentPagePath, rendererConfig, storeTocNode));
+  }
+
+  // call useSWRImmutable again to foce to update cache
+  return useSWRImmutable<RendererOptions, Error>(key);
 };
 
 export const useTocOptions = (): SWRResponse<RendererOptions, Error> => {

+ 5 - 0
yarn.lock

@@ -11606,6 +11606,11 @@ ipaddr.js@1.9.1:
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
   integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
 
+is-absolute-url@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-4.0.1.tgz#16e4d487d4fded05cfe0685e53ec86804a5e94dc"
+  integrity sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==
+
 is-accessor-descriptor@^0.1.6:
   version "0.1.6"
   resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"