背景
公司国际版官网项目,2022年接手时还是nuxt1.0,考虑SEO、性能优化、开发效率的方面,决定将nuxt1.0升级到nuxt2.0:
- 开发迭代超过5年,项目较大,导致本地启动慢,而且热更新时经常内存溢出,需要重新启动,本地开发效率低
- nuxt1.0还使用得是webpack3,无法使用新特性对项目进行性能优化,间接影响网站SEO
- nuxt1.0文档缺失
页面mounted执行两次排查记录
nuxt官方对于mounted执行两次排查的github issue:github.com/nuxt/nuxt/i…
主要原因是客户端渲染时Vue Hydration异常,导致页面在服务端和客户端各执行一次,导致Hydration异常主要有以下几种情况:
第一种 页面布局不合理
比如行内元素内嵌套了块级元素,然后块级元素又使用了for或者if,本地console会报错:
[Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
排要想排查只能一行行代码检查是否是这种情况,最笨的办法:一点点删除代码,看看删除了那一块的代码后不再执行两遍。
第二种 DOM更新前操作DOM
这种情况需要使用this.$nextTick方法在Vue实例的DOM更新完成后执行DOM操作
第三种 layout未设置name
修复代码: github.com/nuxt/nuxt/p… 该问题在V2.12.1已修复
第四种 特殊组件
有些引入的组件会导致执行两边,比如swiper,这种情况除了替换组件,暂时未找到其他解决方法
Google Tag 接入
2023年7月1日起,Google 原UA媒体资源不再处理新的命中数据,需要迁移到GA4媒体资源,通过接入gtag.js代码实现数据收集。正好在这段时间升级nuxt,接入gtag.js代码兼容如下:
// nuxt1.0
npm install @nuxtjs/google-tag-manager
// nuxt.config.js
modules: [
['@nuxtjs/google-tag-manager', { id: 'GTM-xxxxx' }]
]
// nuxt2.0
npm install @nuxtjs/gtm
// nuxt.config.js
modules: [
'@nuxtjs/gtm'
],
gtm: { id: 'GTM-xxxxx' }
CSS 优化
启用 CSS 提取
extractCSS 用于指定是否将组件中的 CSS 提取到单独的 CSS 文件中。
- 当设置为 false 时,CSS 会内联到 HTML 文件中。缺点就是,查看源代码时,head中会有很大篇幅是CSS内容,不知道对SEO是否影响:
- 当设置为 true 时,会生成一个独立的 CSS 文件,因为 nuxt1.0 没有内置
optimization配置项,会打包一个css文件中,这个文件太大,有时会出现网页无样式时长过久。还好nuxt2.0 可以通过配置optimization拆分多个css文件,更有利于缓存和预加载隔离。它还可以只下载和解析所需的资源,从而提高页面性能。
// nuxt.config.js
export default {
build: {
extractCSS: true,
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /.(css|vue)$/,
chunks: 'all',
enforce: true
}
}
}
}
}
}
请注意, Vue 2.5.18 之前存在一个错误,该错误在使用此选项时删除了关键的 CSS 导入。
补充
配置splitChunks后构建会有一个警告信息,来自于 webpack 构建过程中使用了 extract-css-chunks-webpack-plugin 插件。警告信息提到了一个 "Conflicting order"(冲突的顺序)的问题。是因为多个相同组件在不同页面引入的顺序不一致导致,在我一个个定位调整顺序时,我想能不能通过eslint 一键 fixed 所有引入顺序问题,一查还真有 eslint-plugin-import-order,既可以根据字母顺序对每个组内的顺序进行排序,还可以进行分组:
// .eslintrc.js
module.exports = {
plugins: ['import'],
rules: {
'import/order': [
'warn',
{
// - `builtin`:Node.js 内置模块
// - `external`:第三方模块
// - `internal`:项目内部的模块
// - `parent` 和 `sibling`:父级和同级目录中的模块
// - `index`:当前目录下的 `index` 文件
groups: ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index'],
// 字母排序
alphabetize: { order: 'asc', caseInsensitive: true },
'newlines-between': 'always'
}
]
}