Skip to content

Commit

Permalink
feat: render preload links for js and css used during render
Browse files Browse the repository at this point in the history
  • Loading branch information
emuvente committed May 31, 2024
1 parent df9a2dc commit 61e80af
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
5 changes: 2 additions & 3 deletions server/vue-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ export default async function render({
context,
serverConfig,
serverEntry,
// TODO: use ssrManifest to determine which modules to preload
// ssrManifest,
ssrManifest,
template
}) {
const s = Date.now();
Expand Down Expand Up @@ -50,10 +49,10 @@ export default async function render({
setCookies = [...cookieInfo.setCookies];
// render the app
context.template = template;
context.ssrManifest = ssrManifest;
const { html, setCookies: appSetCookies } = await serverEntry(context);
// collect any cookies created during the app render
setCookies = [...setCookies, ...appSetCookies];
info('modules', context.modules);
// send the final rendered html
return {
html,
Expand Down
39 changes: 38 additions & 1 deletion src/server-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,36 @@ function renderExtraHtml(config) {
}
}

// This function renders a <link> tag for a given file
function renderPreloadLink(file) {
if (file.endsWith('.js')) {
return `<link rel="modulepreload" crossorigin href="${file}">`;
}
if (file.endsWith('.css')) {
return `<link rel="stylesheet" href="${file}">`;
}
// TODO: handle other file types if needed
return '';
}

// This function renders <link> tags for all files in the manifest for the given modules
function renderPreloadLinks(modules, manifest = {}) {
let links = '';
const seen = new Set();
modules.forEach(id => {
const files = manifest[id];
if (files) {
files.forEach(file => {
if (!seen.has(file)) {
seen.add(file);
links += renderPreloadLink(file);
}
});
}
});
return links;
}

// This exported function will be called by `bundleRenderer`.
// This is where we perform data-prefetching to determine the
// state of our application before actually rendering it.
Expand All @@ -84,6 +114,7 @@ export default async context => {
user,
locale,
device,
ssrManifest,
template,
} = context;
const { accessToken, ...profile } = user;
Expand Down Expand Up @@ -201,12 +232,17 @@ export default async context => {
// inline the state in the HTML response. This allows the client-side
// store to pick-up the server-side state without having to duplicate
// the initial data fetching on the client.
const payload = await renderSSRHead(head);
const appState = renderGlobals({
__APOLLO_STATE__: apolloClient.cache.extract(),
pageData: buildUserDataGlobal(router, cookieStore, apolloClient)
});

// render head tags
const payload = await renderSSRHead(head);

// render preload links
const preloadLinks = renderPreloadLinks(context.modules, ssrManifest);

// check for 3rd party script opt-out
const hasOptOut = cookies?.kvgdpr?.indexOf('opted_out=true') > -1;

Expand All @@ -217,6 +253,7 @@ export default async context => {
appConfig: renderedConfig,
externals: hasOptOut ? renderedExternals : renderedExternalsOptIn,
googleTagmanagerId: config.googleTagmanagerId,
preloadLinks,
};

return {
Expand Down

0 comments on commit 61e80af

Please sign in to comment.