nuxt搭建论坛填坑记

1,408 阅读3分钟

论坛开发

需求

基础功能(注册、登录、发帖、评论、收藏、点赞等)搭建,需做SEO优化

技术栈

基于Vue实现服务端渲染(SSR),使网站有更好的SEO;选型:nuxt、element-ui

划重点:

Q1 安装

官网推荐安装、创建项目一体:npx create-nuxt-app <my-project>,但是安装报错。

解决:

npm install create-nuxt-app
create-nuxt-app <my-project>

Q2 vuex持久化

1.使用vuex-persistedstate、js-cookie构造插件,不稳定,时而不可用(持久化不起作用);

解决:

使用js-cookie + nuxtServerInit(/store/index.js的actions方法)

login后,将需要持久化的参数写入cookie,在nuxtServerInit中进行取出参数,使用mutations中的方法写入state

参考:blog.csdn.net/qq_30871771…

Q3 axios-headers

axios-headers中增加token认证

1.直接在axios插件中设置token,登录后需要刷新才能设置成功;

解决:

使用中间件(middleware)可行,中间件在页面渲染前执行。 增加axios.js中间件,判断server、client分别取token,并设定context.$axios.setToken(token, 'Bearer')//会设置Authorization

/middleware/axios.js
export default function({$axios,req}){
    let token = null;
    if(process.server){
        if(req.headers.cookie){
            let tokenStr = req.headers.cookie.split(';').find(c=>c.startWith('token=));
            token = tokenStr.split('=')[1];
        }
    }else{
        token = localStorage.getItem('token');
    }
    
    $axios.setToken(token, 'Bearer ') //Bearer token... 此处根据需要加前缀或不加
}

/pages/...xx.vue
//引入中间件
export default{
    middleware:[ "axios" ]
}

Q4 编辑器使用

发帖/评论使用编辑器:选用vue-quill-editor

1.页面直接引入vue-quill-editor、quill-image-super-solution-module,刷新页面报错(如:document is not defined);

原因参考:blog.csdn.net/weixin_3831… (引入第三方vue插件时,即直接使用Import xxx from 'xxx',这种引入方式时,要注意,在第一次刷新页面时也会在服务端进行import,所以会导致大部分vue插件直接报错,解决办法就是:1.要么按照官方文档加载插件的方式进行操作,要么就在mounted钩子中使用动态加载,即let a = require('xxx'))

解决: 在plugins目录下增加插件,在此插件中引入,注册;之后在nuxt.config.js中配置

/plugins/vue-quill-editor.js

import Vue from 'vue'
import Quill from 'quill'
import VueQuillEditor from 'vue-quill-editor'

import {ImageExtend} from 'quill-image-super-solution-module' 
Quill.register('modules/ImageExtend', ImageExtend)  
Vue.use(VueQuillEditor)


/nuxt.config.js

css: ['~/assets/css/index.css',
    'element-ui/lib/theme-chalk/index.css',
    'quill/dist/quill.snow.css',
    'quill/dist/quill.bubble.css',
    'quill/dist/quill.core.css'
  ],
plugins:[
    { src:'@/plugins/vue-quill-editor.js', ssr: false } // 只在客户端渲染
]

/pages/.../xxx.vue
//vue文件中可直接如下使用,此时不用再引入组件(引入组件还是会报上述错误)
//注意class为quill-eitor!!!
<div class="quill-editor"
     :content="posContent"
     @change="onEditorChange($event)"
     @ready="onEditorReady($event)"
     v-quill:myQuillEditor="editorOption">
</div>
//修改帖子:onEditorReady(){this.$emit('input',this.postContent)}可用作回显 
//引入照片上传监听处理函数
beforemount(){
    const { QuillWatch } = require('quill-image-super-solution-module')
    this.editorOption={
        theme: "snow",
        placeholder: "请输入...", // 修改placeholder
        modules:{
            ImageExtend:{
                name: 'file', // upload的参数key
                size: 1, //限制1M大小
                accept: "image/jpg, image/png, image/gif, image/jpeg, image/bmp, image/x-icon", // 允许的图片格式
                editForm(formData){ // 若有增加upload参数的需要,此处可添加到formData
                    formData.append('type',0)
                }, 
                action: '', // upload的api地址
                ... // 更多可查看https://github.com/EthanYan6/quill-image-super-solution-module
            },
            toolbar:{
                container:[
                    ['bold', 'italic', 'underline', 'strike'], ['blockquote', 'code-block'], [{ 'header': 1 }, { 'header': 2 }], [{ 'list': 'ordered' }, { 'list': 'bullet' }], [{ 'script': 'sub' }, { 'script': 'super' }], [{ 'indent': '-1' }, { 'indent': '+1' }], [{ 'direction': 'rtl' }], [{ 'size': ['small', false, 'large', 'huge'] }], [{ 'header': [1, 2, 3, 4, 5, 6, false] }], [{ 'font': [] }], [{ 'color': [] }, { 'background': [] }], [{ 'align': [] }], ['clean'], ['link', 'image', 'video']
                ],
                handlers:{
                    image: function(val){
                        QuillWatch.emit(this.quill.id)
                    }
                }
            }
        }
    }
}

editor相关配置可直接参考github,或示例: github.surmon.me/vue-quill-e…

Q5 部署注意事项

项目部署

  1. 准备环境:

nodejs(服务端渲染需要node环境)、pm2(node进程管理工具)、nginx(配置端口转发,nuxt项目默认启动是3000端口)

*pm2(若是内网服务器,可先在本地全局安装pm2,然后将pm2包上传到服务器,放在(你的nodejs包)/bin/node_modules/路径下,命令文件pm2放在nodejs/bin/路径下)

  1. 启动项目:

pm2 start .../你的项目/node_modules/nuxt/bin/nuxt.js --name package.json中的name //一定要加--name 项目名!!!,否则访问不到项目

BUG:上述启动方式,类似本地npm run dev(nuxt)并不是启动打包后的文件,并且会将dist文件删除掉。由于我是把整个项目放到了服务器,所以没发现这个问题。

解决: 修改启动命令为pm2 start npm --name package.json中的name -- run start

有关启动命令介绍,参考www.w3cschool.cn/nuxtjs/nuxt…

image.png

Q6 端口修改无效

在package.json中加config指定端口,本地启动有效,但对部署在服务器上无效 X 有效,是启动方式的问题,见Q5

Q7 _loading/sse报错

部署后,有个sse推送一直报错 GET http://XXX/_loading/sse net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK) **stackoverflow.com/questions/5…

解决:

启动项目方式的问题,见Q5

Q8 环境配置

step1.新建env.js文件

module.exports = {
    dev: {
        MODE: 'dev',
        ENV_API: 'http://xxx'
    },
    sit: {
        MODE: 'sit',
        ENV_API: 'http://xxx'
    }
}

step2.nuxt.config.js中引入

const env = require('./env')

//配置:
 publicRuntimeConfig: {
    axios: {
        baseURL: env[process.env.MODE].ENV_API
    }
},
axios: {
    baseURL: env[process.env.MODE].ENV_API
},
env: {
        baserUrl: env[process.env.MODE].ENV_API //.vue中有需要可使用process.env.baseUrl来获取api
}

step3.配置package.json

    "scripts": {
        "dev": "cross-env MODE=dev nuxt",
        "sit": "cross-env MODE=sit nuxt",
        "build": "cross-env MODE=dev nuxt build",
        "sit:build": "cross-env MODE=sit nuxt build",
        "start": "nuxt start",
        "generate": "nuxt generate",
        "lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
        "lint": "npm run lint:js"
    },

*参考blog.csdn.net/weixin_4578…


记录有误操作:

使用vuex-persistedstate、js-cookie持久化,不稳定,时而有用时而无用,如下:

import createPersistedState from 'vuex-persistedstate';
import * as Cookies from "js-cookie";

let cookieStorage = {
    getItem: function(key) {
        return Cookies.getJSON(key);
    },
    setItem: function(key, value) {
        return Cookies.set(key, value, { expires: 3, secure: false });
    },
    removeItem: function(key) {
        return Cookies.remove(key);
    }
};

export default (context) => {
    console.log('plugin', context)
    createPersistedState({
        storage: cookieStorage,
        getState: cookieStorage.getItem,
        setState: cookieStorage.setItem
    })(context.store);
};