Nuxt.js常见问题和优化

1. 常见问题和解决方案

1.1 NuxtServerError connect ECONNREFUSED 127.0.0.1:80

原因: asyncData方法异步请求数据时,以为/api/${params.id}这个接口的网址是 127.0.0.1:80, 所以将请求发送给了127.0.0.1:80,而我的接口服务器并没有跑在80端口上,所以报错。

解决方法:

  1. 将node服务器端口改成 127.0.0.1:80
  2. 将接口服务器端口改成 127.0.0.1:80
  3. 将asyncData方法使用的请求url加上域名+端口,如下所示
export default {
    
    
  asyncData ({
    
     params }) {
    
    
    return axios.get(`https://127.0.0.1:3000/api/${
     
     params.id}`)
    .then((res) => {
    
    
      return {
    
     title: res.data.title }
    })
  }
}

1.2 如何在 head 里面引入js文件?

背景: 在<head>标签中,以inline的形式引入flexible.js文件。本项目主要为移动端项目,引入flexible.js 实现移动端适配问题。

Nuxt.js 通过 vue-meta 实现头部标签管理,通过查看文档发现,可以按照如下方式配置:

head: {
    
    
  script: [{
    
     innerHTML: require('./assets/js/flexible'), type: 'text/javascript', charset: 'utf-8'}],
  __dangerouslyDisableSanitizers: ['script']
}

1.3 nuxt使用less,sass等预处理器

背景:在组件中的<template><script><style> 上使用各种预处理器,加上处理器后,控制台报错。

npm install --save-dev node-sass sass-loader

但是解决过程并不是很顺利的,在阅读中文文档时,忽略版本号,按照上面的提示进行操作,发现不能成功,后来各种debug,最后发现了该解决方案。后知后觉的发现了中文文档的版本号过低,如果需要查看文档,一定要看最新版本的英文文档!

1.4 如何使用px2rem

背景:在css中,写入px,通过px2rem loader,将px转换成rem

在以前的项目中,是通过 px2rem loader实现的,但是在Nuxt.js项目下,添加 css loader 还是很费力的,因为涉及到vue-loader

想到了一个其他方案,可以使用 postcss 处理。可以在 nuxt.config.js 文件中添加配置,也可以在postcss.conf.js文件中添加。

build: {
    
    

  postcss: [
    require('postcss-px2rem')({
    
    
      remUnit: 75 // 转换基本单位
    })
  ]
},

1.5 如何拓展 webpack 配置

背景:给 utils 目录添加别名

刚刚说到,Nuxt.js内置了 webpack 配置,如果想要拓展配置,可以在 nuxt.config.js 文件中添加。同时也可以在该文件中,将配置信息打印出来。

extend (config, ctx) {
    
    
  console.log('webpack config:', config)
  if (ctx.isClient) {
    
    
    // 添加 alias 配置
    Object.assign(config.resolve.alias, {
    
    
      'utils': path.resolve(__dirname, 'utils')
    })
  }
}

1.6 如何添加 vue plugin

背景:自己封装了一个 toast vue plugin,由于 vue 实例化的过程没有暴露出来,不知道在哪个时机注入进去。

可以在 nuxt.config.js 中添加 plugins 配置,这样插件就会在 Nuxt.js 应用初始化之前被加载导入。

module.exports = {
    
    
  plugins: ['~plugins/toast']
}

~plugins/toast.js 文件:

import Vue from 'vue'
import toast from '../utils/toast'
import '../assets/css/toast.css'
Vue.use(toast)

1.7 如何修改环境变量 NODE_ENV

背景:在项目中,设置 3个 NODE_ENV 的值,来对应不同的版本。development,本地开发;release,预发布版本;production,线上版本。其中,预发布版本比production版本,多出vconsole。

// package.json
"scripts": {
    
    
  "buildDev": "cross-env NODE_ENV=release nuxt build && backpack build",
  "startDev": "cross-env NODE_ENV=release PORT=3000 node build/main.js"
  },

打印 process.env.NODE_ENV 依旧是,production

在 backpack 的源码中,找到了答案,在 执行 backpack build 命令时,会把 process.env.NODE_ENV 修改为 production,并且是写死的不可配置的…

无奈下,只能在 process.env 下,添加 __ENV 属性,代表 NODE_ENV

这时,在页面中打印出来的信息 process.env.__ENV undefined,但是可以打印出 process.env.NODE_ENV

可以通过配置 nuxt.config.js 中的,env属性,解决该问题。

env: {
    
    
  __ENV: process.env.__ENV
}

1.8 Window 或 Document 对象未定义?

背景: 在引入第三方插件,或者直接在代码中写 window 时,控制台会给出警告,window 未定义。

发生在这个问题的原因时,node服务端并没有windowdocument 对象。解决方法,通过 process.browser 来区分环境。

if (process.browser) {
    
    
  // 引入第三方插件
  require('***')
  // 或者修改window对象下某一属性
  window.mbk = {
    
    }
}

1.9 按需引入(UI框架等等)

例如使用UI框架:element-ui

我找了很多相关文章,并没有详细说明该如何引入。所以我要拿出来将他说明:

先来看下,如果不按需引入vendor.js的体积大小为:

第一步,下载依赖:

# 先下载element-ui
npm install element-ui --save

# 如果使用按需引入,必须安装babel-plugin-component(官网有需要下载说明,此插件根据官网规则不同,安装插件不同)

npm install babel-plugin-component --save-dev

安装好以后,按照nuxt.js中的规则,你需要在 plugins/ 目录下创建相应的插件文件

文件根目录创建(或已经存在)plugins/目录,创建名为:element-ui.js的文件,内容如下:

import Vue from 'vue'
import {
    
     Button } from 'element-ui'    //引入Button按钮

export default ()=>{
    
    
    Vue.use(Button)
}

第二步,引入插件

nuxt.config.js中,添加配置为:plugins

css:[
'element-ui/lib/theme-chalk/index.css'
],
plugins:[
'~/plugins/element-ui'
]

默认为:开启SSR,采用服务端渲染,也可以手动配置关闭SSR,配置为:

css:[
'element-ui/lib/theme-chalk/index.css'
],

plugins:[
    {
    
    
        src:'~/plugins/element-ui',
        ssr:false    //关闭ssr
    }
]

第三步,配置babel选项

nuxt.config.js中,配置在build选项中,规则为官网规则:

build: {
    
    
      babel:{
    
            //配置按需引入规则
          "plugins":[
              [
                  "component",
                  {
    
    
                      "libraryName":"element-ui",
                      "styleLibraryName":"theme-chalk"
                  }
              ]
          ]
      },
    /*
     ** Run ESLINT on save
     */
    extend (config, ctx) {
    
    
      if (ctx.isClient) {
    
    
        config.module.rules.push({
    
    
           enforce: 'pre',
           test: /\.(js|vue)$/,
           loader: 'eslint-loader',
           exclude: /(node_modules)/
        })
      }
    }
 }

此时,我们在观察打包以后文件体积大小,如图:

此时,我们成功完成了按需引入配置。

1.10 不想服务端渲染的地方

(1)
<no-ssr>
	插件或者组件
</no-ssr>

(2)
nuxt.config.js里ssr改为false
plugins: [
    {
    
    src: '~/plugins/ElementUI', ssr: false }
],

1.11 nuxt必须在接口地址前加上访问域名

解决: 可以使用axios的baseURL来代理

import Vue from 'vue'
import axios from 'axios'
// axios.defaults.baseURL = "http://www.huanjingwuyou.com/"

axios.defaults.baseURL = "http://localhost:3000/"
// axios.defaults.baseURL = "http://test.huanjingwuyou.com/"

export default axios

2. 总结:

  1. nuxt渲染页面分为两个阶段, 服务端渲染和浏览器渲染
  2. nuxt可以用服务端渲染阶段asyncData来提前获取到数据, 数据自动存放到data中, 浏览器渲染时直接拿data数据
  3. asyncData方法会在组件(限于页面组件)每次会在刷新加载页面或者切换路由时被调用,顺序比beforeCreate和created之前
  4. nuxt服务端渲染时生命周期只有两个钩子函数created和beforeCreate两个钩子函数,
  5. async做并发请求
  6. 设置head来提高SEO, 局部需要return {}
  7. 每次调用接口的时候需要在接口前面加上访问域名, 可以通过axios配置axios.defaults.baseURL
  8. nuxt用proxy来代理
  9. 跳到详情页用nuxt-link来跳转, 这样url地址参数更有利于seo, 跳转时域名都是自己拼接上去的
  10. 写一个错误页面, 路由调用失败或者代码出现bug, 会跳到错误页面去
  11. 公共的静态页面可以写在assets里, 然后nuxt.config.js里引入
  12. 发布线上时需要将.nuxt, assets, package.json, nuxt.config.js, static放到Nginx里进行代理

3. BUG以及解决方案

3.1 如何在组件中使用异步数据?

如果组件不是和路由绑定的页面组件,原则上是不可以使用异步数据的。因为 Nuxt.js 仅仅扩展增强了页面组件的 data 方法,使得其可以支持异步数据处理。

对于非页面组件,有两种方式可以实现数据的异步获取:

  1. 在组件的 mounted 方法里面实现异步获取数据的逻辑,之后设置组件的数据,限制是:不支持服务端渲染。
  2. 在页面组件的asyncDatafetch方法中进行API调用,并将数据作为props传递给子组件。服务器渲染工作正常。缺点:asyncData或页面提取可能不太可读,因为它正在加载其他组件的数据。 总之,使用哪种方法取决于你的应用是否需要支持子组件的服务端渲染。

3.2 为什么 Nuxt.js 应用的页面会出现闪烁?

这是因为在开发模式下,为了通过 Webpack 实现热加载,CSS代码是打包在 JavaScript 代码中,并动态打到页面中去,从而元素重绘引起了闪烁。

不用担心,在生产模式下,CSS代码会单独打包至独立的文件并置于head标签内,不会出现页面闪烁的现象。

3.3 如何编辑主机和端口配置?

作为命令参数直接传递

nuxt --hostname myhost --port 3333

"scripts": {
    
    
  "dev": "nuxt --hostname myhost --port 3333"
}

nuxt.config.js 中配置:

nuxt.config.js 添加:

export default {
    
    
  server: {
    
    
    port: 8000, // default: 3000
    host: '0.0.0.0', // default: localhost
  },
  // other configs
}

使用 NUXT_HOST 和 NUXT_PORT env 变量

与 HOST 和 PORT 类似,但更具体,以防您需要添加其他东西。

"scripts": {
    
    
  "dev": "NUXT_HOST=0.0.0.0 NUXT_PORT=3333 nuxt"
}

注意: 为了更好的跨平台开发支持,您可以使用 cross-env 依赖包。

安装依赖:

npm install --save-dev cross-env

配置cross-env:

"scripts": {
    
    
  "dev": "cross-env NUXT_HOST=0.0.0.0 NUXT_PORT=3333 nuxt"
}

使用HOST和PORT env变量

"scripts": {
    
    
  "dev": "HOST=0.0.0.0 PORT=3333 nuxt"
}

package.json 中配置 nuxt :

在您的 package.json 文件中添加:

"config": {
    
    
  "nuxt": {
    
    
    "host": "0.0.0.0",
    "port": "3333"
  }
},
"scripts": {
    
    
  "dev": "nuxt"
}

3.4 给nuxt的localhost配置https

  1. 安装 mkcert:
brew install mkcert
brew install nss #如果用火狐浏览器安装nss
  1. 将mkcert添加到本地根CAs:
mkcert -install
  1. 终端切换到项目根目录,然后运行命令生成文件:
mkcert localhost
  1. 把证书添加到 nuxt.config.js:
import path from 'path'
import fs from 'fs'
server: {
    
    
    https: {
    
    
        key: fs.readFileSync(path.resolve(__dirname, 'localhost-key.pem')),
        cert: fs.readFileSync(path.resolve(__dirname, 'localhost.pem'))
    }
}

猜你喜欢

转载自blog.csdn.net/qq_36228377/article/details/123642604