NuxtJS V2 优化

·408 Views·

以下这些都是在项目中实践过的优化方法,不过现在 Nuxt 升级到 V3 了,这些方法都不适用了。

移除未使用的CSS

1render: {
2 route: (url, result) => {
3 // Tailwindcss 内联到 html 中是未压缩的,原因未知
4 // 所以在 render 时使用 cleanCSS 压缩
5 const { html } = result;
6 const STYLE_PATTERN = /<style[^>]*>([\\s\\S]*?)<\\/[^>]*style>/gi;
7 const replaceHTML = html.replace(STYLE_PATTERN, ($0, $1) => {
8 const context = [];
9 context.push('<style>');
10 const { styles } = new CleanCSS().minify($1);
11 context.push(styles);
12 context.push('</style>');
13 return context.join('');
14 });
15 result.html = replaceHTML;
16 },
17 }

动态增加Script

1hooks: {
2 route: (url, result, { req }) => {
3 // 支付宝小程序,需要加入特定的 js
4 // 目前轻交互会在小程序打开
5 const { headers } = req;
6 const { html } = result;
7 const userAgent = headers['user-agent'] || '';
8 const isAliAPP = userAgent.toLocaleLowerCase().includes('aliapp');
9 if (!isAliAPP) {
10 return;
11 }
12 const aliAPPScript =
13 '<script src="<https://appx/web-view.min.js>"></script></head>';
14 result.html = html.replace(/<\\/head>/i, aliAPPScript);
15 },
16 }

减少__Nuxt__体积

NuxtJS 在使用服务端渲染时,会自动往HTML注入当前页面使用的数据,对于只有渲染的页面,在客户端根本用不到这些数据,如果是列表页面,这些数据会偏大,导致整个页面体积变大,造成传输耗时。

诉求是:把用不到的这些数据在页面渲染时去掉。

方案是:利用 NuxtJS 提供的渲染 Hook 解决,代码如下:

1hooks: {
2 'vue-renderer': {
3 'ssr:templateParams': (templateParams, renderContext) => {
4 const { APP } = templateParams;
5 const { nuxt } = renderContext;
6 const { ...state } = nuxt;
7 const { config } = state;
8 // 去掉 window.__NUXT__ 没有用的信息,只保留环境信息,减少页面体积
9 // 环境信息是必须的,不能去掉
10 const PATTERN = /<script>window\\.__NUXT__=([\\s\\S]*?)<\\/[^>]*script>/i;
11 const replaceHTML = APP.replace(PATTERN, () => {
12 const stateScript = `window.__NUXT__=${devalue({
13 config,
14 })};`;
15 return `<script>${stateScript}</script>`;
16 });
17 Object.assign(templateParams, {
18 APP: replaceHTML,
19 });
20 },
21 },
22},

增加页面级缓存

在 middleware 新建 page-cache.js ,代码如下:

1const LRU = require('lru-cache');
2export const CACHE = new LRU({
3 // 缓存队列长度 最大缓存数量
4 max: 100,
5 // 缓存时间 单位:毫秒
6 maxAge: 1000 * 60 * 60 * 24,
7});
8export default (req, res, next) => {
9 if (process.env.NODE_ENV !== 'production') {
10 next();
11 return;
12 }
13 const cacheKey = 'NPS_PAGE';
14 const cacheObj = CACHE.get(cacheKey);
15 if (cacheObj) {
16 res.setHeader('Content-Type', ' text/html; charset=utf-8');
17 res.end(cacheObj.html, 'utf-8');
18 return;
19 }
20 res.original_end = res.end;
21 res.end = (data) => {
22 if (res.statusCode === 200) {
23 CACHE.set(cacheKey, {
24 html: data,
25 });
26 }
27 res.original_end(data, 'utf-8');
28 };
29 next();
30};

在 nuxt.config.js 中启用:

serverMiddleware: ['~/middleware/page-cache.js'],

增加模版变量

uxtJS 在渲染页面时,只有固定几个变量,比如:APP、ENV、HEAD 等。而这些远远满足不了自定义的需求。

举个现实的场景:项目中,有些页面使用灵犀系统上报埋点,有些页面不使用,如果把灵犀代码放到统一的页面入口中,对于不使用灵犀的页面而言,反而增加了一个多余的网络请求,影响页面性能。

我们的诉求是,能根据页面路径,动态的追加灵犀代码。

这就需要借助 NuxtJS 提供的 Hooks 来支持。在 nuxt.config.js 增加 hooks ,代码如下:

1hooks: {
2 'vue-renderer': {
3 'ssr:templateParams': (templateParams, renderContext) => {
4 const { nuxt } = renderContext;
5 const { routePath } = nuxt || {};
6 const whiteList = [
7 '/light-portal.html',
8 '/light-portal/material-detail.html',
9 '/light-portal/material.html',
10 ];
11 // 只有特定页面才加入灵犀
12 const shouldAppendLX = whiteList.includes(routePath);
13 // 追加 IS_APPEND_LX 全局变量,便于在页面中使用
14 Object.assign(templateParams, {
15 IS_APPEND_LX: shouldAppendLX,
16 });
17 },
18 },
19}

在 app.html 使用 「IS_APPEND_LX」变量动态输出 灵犀脚本:

1{% if (IS_APPEND_LX) { %}
2 <script src="//lx.meituan.net/lx.5.min.js"></script>
3 <script>
4 !function(n,t,e){if(n["_MeiTuanALogObject"]=e,!n[e]){var u=function(){let n=function(){let t=function(){t.q.push([arguments,+new Date])};return t.q=[],n.q.push([arguments,t]),t};return n.q=[],n.t=+new Date,u.q.push([arguments,n]),n};u.q=u.q||[],u.l=+new Date,n[e]=u}}(window,document,"LXAnalytics");
5 LXAnalytics('config', {
6 defaultCategory:'cs_smart_portal',
7 defaultCid: 'c_cs_smart_portal_ntwfxrrs',
8 isSPA: false,
9 isDev: {{ process.env.ENV !== 'prod' }},
10 onWebviewAppearAutoPV: false,
11 onVisibilityChangeAutoPV: false,
12 onWindowFocusAutoPV: false,
13 onVCGap: 2,
14 nativeReport:'off',
15 use_post: true,
16 });
17 </script>
18{% } %}