From 786e746d811d42524ff10c226ca261776f56c945 Mon Sep 17 00:00:00 2001 From: PeachScript Date: Fri, 26 Jan 2024 11:32:29 +0800 Subject: [PATCH] refactor: prefetch to preload and extract as utils --- packages/preset-umi/.fatherrc.ts | 4 +- .../src/client/prefetchRouteFilesScp.ts | 19 ------ .../src/client/preloadRouteFilesScp.ts | 48 +++++++++++++++ .../routePrefetch/prefetchRouteFiles.ts | 58 ------------------- .../features/routePrefetch/routePrefetch.ts | 10 ++-- .../src/features/routePrefetch/utils.ts | 46 +++++++++++++++ .../routePrefetch/prefetchRouteFilesScp.js | 1 - .../routePrefetch/preloadRouteFilesScp.js | 1 + 8 files changed, 102 insertions(+), 85 deletions(-) delete mode 100644 packages/preset-umi/src/client/prefetchRouteFilesScp.ts create mode 100644 packages/preset-umi/src/client/preloadRouteFilesScp.ts delete mode 100644 packages/preset-umi/src/features/routePrefetch/prefetchRouteFiles.ts create mode 100644 packages/preset-umi/src/features/routePrefetch/utils.ts delete mode 100644 packages/preset-umi/templates/routePrefetch/prefetchRouteFilesScp.js create mode 100644 packages/preset-umi/templates/routePrefetch/preloadRouteFilesScp.js diff --git a/packages/preset-umi/.fatherrc.ts b/packages/preset-umi/.fatherrc.ts index f170d7a59599..7c7163545da6 100644 --- a/packages/preset-umi/.fatherrc.ts +++ b/packages/preset-umi/.fatherrc.ts @@ -6,10 +6,10 @@ export default defineConfig({ ignores: ['src/client/*'], }, umd: { - entry: 'src/client/prefetchRouteFilesScp.ts', + entry: 'src/client/preloadRouteFilesScp.ts', output: 'templates/routePrefetch', chainWebpack(memo) { - memo.output.filename('prefetchRouteFilesScp.js'); + memo.output.filename('preloadRouteFilesScp.js'); memo.output.delete('libraryTarget'); memo.output.iife(true); diff --git a/packages/preset-umi/src/client/prefetchRouteFilesScp.ts b/packages/preset-umi/src/client/prefetchRouteFilesScp.ts deleted file mode 100644 index 8241232fa50f..000000000000 --- a/packages/preset-umi/src/client/prefetchRouteFilesScp.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * NOTE: DO NOT USE ADVANCED SYNTAX IN THIS FILE, TO AVOID INSERT HELPERS TO REDUCE SCRIPT SIZE. - */ - -import prefetchRouteFiles from '../features/routePrefetch/prefetchRouteFiles'; - -const basename = '{{basename}}'; -const publicPath = '{{publicPath}}'; -const pathname = location.pathname; -const routePath = - pathname.startsWith(basename) && - decodeURI(`/${pathname.slice(basename.length)}`); - -// skip prefetch if basename not match -if (routePath) { - prefetchRouteFiles(routePath, '{{routeChunkFilesMap}}' as any, { - publicPath, - }); -} diff --git a/packages/preset-umi/src/client/preloadRouteFilesScp.ts b/packages/preset-umi/src/client/preloadRouteFilesScp.ts new file mode 100644 index 000000000000..306a2a403113 --- /dev/null +++ b/packages/preset-umi/src/client/preloadRouteFilesScp.ts @@ -0,0 +1,48 @@ +/** + * NOTE: DO NOT USE ADVANCED SYNTAX IN THIS FILE, TO AVOID INSERT HELPERS TO REDUCE SCRIPT SIZE. + */ + +import { getPreloadRouteFiles } from '../features/routePrefetch/utils'; + +const basename = '{{basename}}'; +const publicPath = '{{publicPath}}'; +const pathname = location.pathname; +const routePath = + pathname.startsWith(basename) && + decodeURI(`/${pathname.slice(basename.length)}`); + +// skip preload if basename not match +if (routePath) { + const map = '{{routeChunkFilesMap}}' as any; + const doc = document; + const head = doc.head; + const createElement = doc.createElement.bind(doc); + const files = getPreloadRouteFiles(routePath, map, { + publicPath, + }); + + files?.forEach((file) => { + const type = file.type; + const url = file.url; + let tag: HTMLLinkElement | HTMLScriptElement; + + if (type === 'js') { + tag = createElement('script'); + tag.src = url; + tag.async = true; + } else if (type === 'css') { + tag = createElement('link'); + tag.href = url; + tag.rel = 'preload'; + tag.as = 'style'; + } else { + return; + } + + file.attrs.forEach((attr) => { + tag.setAttribute(attr[0], attr[1] || ''); + }); + + head.appendChild(tag); + }); +} diff --git a/packages/preset-umi/src/features/routePrefetch/prefetchRouteFiles.ts b/packages/preset-umi/src/features/routePrefetch/prefetchRouteFiles.ts deleted file mode 100644 index 0039ffcbab4f..000000000000 --- a/packages/preset-umi/src/features/routePrefetch/prefetchRouteFiles.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * NOTE: DO NOT USE ADVANCED SYNTAX IN THIS FILE, TO AVOID INSERT HELPERS TO REDUCE SCRIPT SIZE. - */ - -import type { IRouteChunkFilesMap } from './routePrefetch'; - -export const PREFETCH_ROUTE_MAP_SCP_TYPE = 'umi-route-chunk-files-map'; - -function prefetchRouteFiles( - path: string, - map: IRouteChunkFilesMap, - opts: { publicPath: string }, -) { - const doc = document; - const head = doc.head; - const createElement = doc.createElement.bind(doc); - const publicPath = opts.publicPath; - let matched: IRouteChunkFilesMap['r'][string] | undefined = - // search for static route - map.r[path] || - // search for dynamic route - Object.entries(map.r).find((p) => { - const route = p[0]; - const reg = new RegExp( - // replace /:id to /[^/]+ - // replace /* to /.+ - `^${route.replace(/\/:[^/]+/g, '/[^/]+').replace('/*', '/.+')}$`, - ); - - return reg.test(path); - })?.[1]; - - matched?.forEach((i) => { - const id = map.f[i][1]; - const file = map.f[i][0]; - const ext = file.split('.').pop(); - let tag: HTMLLinkElement | HTMLScriptElement; - - if (ext === 'js') { - tag = createElement('script'); - tag.src = `${publicPath}${file}`; - tag.async = true; - } else if (ext === 'css') { - tag = createElement('link'); - tag.href = `${publicPath}${file}`; - tag.rel = 'preload'; - tag.as = 'style'; - } else { - return; - } - - tag.setAttribute(`data-${map.b}`, `${map.p}:${id}`); - - head.appendChild(tag); - }); -} - -export default prefetchRouteFiles; diff --git a/packages/preset-umi/src/features/routePrefetch/routePrefetch.ts b/packages/preset-umi/src/features/routePrefetch/routePrefetch.ts index 25b248019a71..f0b0a9f16d66 100644 --- a/packages/preset-umi/src/features/routePrefetch/routePrefetch.ts +++ b/packages/preset-umi/src/features/routePrefetch/routePrefetch.ts @@ -5,7 +5,7 @@ import { dirname, isAbsolute, join, relative } from 'path'; import { TEMPLATES_DIR } from '../../constants'; import { createResolver } from '../../libs/scan'; import type { IApi, IRoute } from '../../types'; -import { PREFETCH_ROUTE_MAP_SCP_TYPE } from './prefetchRouteFiles'; +import { PRELOAD_ROUTE_MAP_SCP_TYPE } from './utils'; export interface IRouteChunkFilesMap { /** @@ -95,7 +95,7 @@ export default (api: IApi) => { ? // map mode [ { - type: PREFETCH_ROUTE_MAP_SCP_TYPE, + type: PRELOAD_ROUTE_MAP_SCP_TYPE, content: JSON.stringify(routeChunkFilesMap), }, ] @@ -103,7 +103,7 @@ export default (api: IApi) => { [ { content: readFileSync( - join(TEMPLATES_DIR, 'routePrefetch/prefetchRouteFilesScp.js'), + join(TEMPLATES_DIR, 'routePrefetch/preloadRouteFilesScp.js'), 'utf-8', ) .replace( @@ -147,7 +147,7 @@ export default (api: IApi) => { ); } catch (err) { logger.error( - `[routePrefetch]: route file resolve error, cannot prefetch for ${origin.request!}`, + `[routePrefetch]: route file resolve error, cannot preload for ${origin.request!}`, ); continue; } @@ -205,7 +205,7 @@ export default (api: IApi) => { files.push(fileAbsPath); } catch { logger.error( - `[routePrefetch]: route file resolve error, cannot prefetch for ${current.file}`, + `[routePrefetch]: route file resolve error, cannot preload for ${current.file}`, ); } current = current.parentId && api.appData.routes[current.parentId]; diff --git a/packages/preset-umi/src/features/routePrefetch/utils.ts b/packages/preset-umi/src/features/routePrefetch/utils.ts new file mode 100644 index 000000000000..2790ed10f1b1 --- /dev/null +++ b/packages/preset-umi/src/features/routePrefetch/utils.ts @@ -0,0 +1,46 @@ +/** + * NOTE: DO NOT USE ADVANCED SYNTAX IN THIS FILE, TO AVOID INSERT HELPERS TO REDUCE SCRIPT SIZE. + */ + +import type { IRouteChunkFilesMap } from './routePrefetch'; + +interface IPreloadRouteFile { + type: 'js' | 'css' | unknown; + url: string; + attrs: ([string, string] | [string])[]; +} + +export const PRELOAD_ROUTE_MAP_SCP_TYPE = 'umi-route-chunk-files-map'; + +export function getPreloadRouteFiles( + path: string, + map: IRouteChunkFilesMap, + opts: { publicPath: string }, +): IPreloadRouteFile[] | undefined { + const matched: IRouteChunkFilesMap['r'][string] | undefined = + // search for static route + map.r[path] || + // search for dynamic route + Object.entries(map.r).find((p) => { + const route = p[0]; + const reg = new RegExp( + // replace /:id to /[^/]+ + // replace /* to /.+ + `^${route.replace(/\/:[^/]+/g, '/[^/]+').replace('/*', '/.+')}$`, + ); + + return reg.test(path); + })?.[1]; + + return matched?.map((i) => { + const id = map.f[i][1]; + const file = map.f[i][0]; + const ext = file.split('.').pop(); + + return { + type: ext, + url: `${opts.publicPath}${file}`, + attrs: [[`data-${map.b}`, `${map.p}:${id}`]], + }; + }); +} diff --git a/packages/preset-umi/templates/routePrefetch/prefetchRouteFilesScp.js b/packages/preset-umi/templates/routePrefetch/prefetchRouteFilesScp.js deleted file mode 100644 index d827f694404b..000000000000 --- a/packages/preset-umi/templates/routePrefetch/prefetchRouteFilesScp.js +++ /dev/null @@ -1 +0,0 @@ -!function(){"use strict";var t=function(t,c,e){var n,a=document,i=a.head,r=a.createElement.bind(a),o=e.publicPath,l=c.r[t]||(null===(n=Object.entries(c.r).find((function(c){var e=c[0];return new RegExp("^".concat(e.replace(/\/:[^/]+/g,"/[^/]+").replace("/*","/.+"),"$")).test(t)})))||void 0===n?void 0:n[1]);null==l||l.forEach((function(t){var e,n=c.f[t][1],a=c.f[t][0],l=a.split(".").pop();if("js"===l)(e=r("script")).src="".concat(o).concat(a),e.async=!0;else{if("css"!==l)return;(e=r("link")).href="".concat(o).concat(a),e.rel="preload",e.as="style"}e.setAttribute("data-".concat(c.b),"".concat(c.p,":").concat(n)),i.appendChild(e)}))},c="{{basename}}",e=location.pathname,n=e.startsWith(c)&&decodeURI("/".concat(e.slice(c.length)));n&&t(n,"{{routeChunkFilesMap}}",{publicPath:"{{publicPath}}"})}(); \ No newline at end of file diff --git a/packages/preset-umi/templates/routePrefetch/preloadRouteFilesScp.js b/packages/preset-umi/templates/routePrefetch/preloadRouteFilesScp.js new file mode 100644 index 000000000000..732380820ba8 --- /dev/null +++ b/packages/preset-umi/templates/routePrefetch/preloadRouteFilesScp.js @@ -0,0 +1 @@ +!function(){"use strict";var t="{{basename}}",e=location.pathname,n=e.startsWith(t)&&decodeURI("/".concat(e.slice(t.length)));if(n){var a=document,c=a.head,r=a.createElement.bind(a),i=function(t,e,n){var a,c=e.r[t]||(null===(a=Object.entries(e.r).find((function(e){var n=e[0];return new RegExp("^".concat(n.replace(/\/:[^/]+/g,"/[^/]+").replace("/*","/.+"),"$")).test(t)})))||void 0===a?void 0:a[1]);return null==c?void 0:c.map((function(t){var a=e.f[t][1],c=e.f[t][0];return{type:c.split(".").pop(),url:"".concat(n.publicPath).concat(c),attrs:[["data-".concat(e.b),"".concat(e.p,":").concat(a)]]}}))}(n,"{{routeChunkFilesMap}}",{publicPath:"{{publicPath}}"});null==i||i.forEach((function(t){var e,n=t.type,a=t.url;if("js"===n)(e=r("script")).src=a,e.async=!0;else{if("css"!==n)return;(e=r("link")).href=a,e.rel="preload",e.as="style"}t.attrs.forEach((function(t){e.setAttribute(t[0],t[1]||"")})),c.appendChild(e)}))}}(); \ No newline at end of file