nuxt构建项目

Posted 万年打野易大师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nuxt构建项目相关的知识,希望对你有一定的参考价值。

一、引入并创建nuxt项目

确认已经安装 npx ( npx 依附于 npm 5.2.0 安装引入)

npx create-nuxt-app <my-project>

或者在 npm v6.1版本后 可以这样创建:

npm init nuxt-app@latest <my-project>

或者用: yarn:

yarn create nuxt-app <my-project>

二、引入axios

1、使用nuxt自带模块

npm i @nuxtjs/axios -s

1) 、在 nuxt.config.js 中引入

export default {
  /*
   ** Runtime Config
   */
  publicRuntimeConfig: {
    axios: {
      baseURL: \'https://api.nuxtjs.dev\'
    }
  },
  /*
   ** Modules - https://nuxtjs.org/docs/2.x/directory-structure/modules
   */
  modules: [\'@nuxtjs/axios\']
}

2) 、页面内使用 $axios 获取数据,并用 $config 获取 API 接口的 URL

async asyncData({$axios}) {
  let { res } = await $axios.get(`https://xxx.com/api/xxx`) 
  console.log(res)    
}

3) 、设置公共拦截

~/plugins 创建 axios.js 文件

export default function ({store, redirect, req, router, $axios })  {
    // baseUrl可以在上面的配置中,也可在这儿配置
    $axios.defaults.baseURL = \'http://XXX/api\';
    if(process.server){
        // 获取服务端的token,对应函数请自行封装
        var token = getcookiesInServer(req).token;
    }
    if(process.client){
        // 获取客户端token,对应函数请自行封装
        var token = getcookiesInClient(\'token\');
    }
    // request拦截器
    $axios.onRequest(config => {
        if(process.client){
            // 客户端下,请求进度条开始
            NProgress.start();
        }
        // 将获取到token加入到请求头中
        config.headers.common[\'Authorization\'] = token;
    });
    // response拦截器,数据返回后,可以先在这里进行一个简单的判断
    $axios.interceptors.response.use(
        response => {
            if(process.client){
                // 客户端下, 请求进度条结束
                NProgress.done();
            }
            // return response
            if(response.data.code == 401){
                // 返回401,token验证失败
                removeToken("token");
                  // 重定向到登录页面, 这里做一个判断,容错:req.url 未定义
                if(req.url){
                    redirect("/sign?ref="+req.url)
                }else{
                    redirect("/sign")
                }
            }else if(response.data.code == 404){
                // 重定向到404页面
                redirect("/")
            }
            else{
                // 请求接口数据正常,返回数据
                return response
            }
        },
        error => {
            if(process.client){
                NProgress.done();
            }
            if(error.response.status == 500){
                // http状态500,服务器内部错误,重定向到500页面
                redirect("/500.htm")
            }
            if(error.response.status == 404){
                // http状态500,请求API找不到,重定向到404页面
                redirect("/404.html")
            }
            return Promise.reject(error.response)   // 返回接口返回的错误信息
        })
}

2、外部引入axios

npm i axios -s

1) 、创建request文件夹

在文件夹内创建 http.js文件, urls文件夹, apis文件夹

http.js

import axios from \'axios\'
import Vue from \'vue\'

const ajax = axios.create({
    baseURL: process.env.baseUrl,
    timeout: 30 * 1000
})

// 请求拦截器
ajax.interceptors.request.use(
    config => {
        // const Token = getToken()
        // if (Token) {
        //     config.headers[\'token\'] = getToken()
        // }
        config.headers[\'Content-Type\'] = \'application/json;chartset=utf-8\'
        // config.headers["Authorization"] = "Bearer atwerjjhqkwehtjhsdfqwehjhwrgqre";
        return config
    },
    error => {
        throw new Error(`请求错误: ${error}`)
    }
)
// 响应拦截器
ajax.interceptors.response.use(
    response => {
        if (response.status === 200) {
            // 处理返回流文件报错
            if (response.config.responseType === \'blob\') {
                var reader = new FileReader()
                reader.readAsText(response.data)
                reader.onload = e => {
                    const result = JSON.parse(e.target.result)
                    if (result.code !== 200) {
                        Vue.prototype.$message.error(result.msg)
                    }
                }
            }
            if (response.data.code === 200) {
                return response.data.data
            } else {
                Vue.prototype.$message.error(response.data.message)
                return Promise.reject(response.data)
            }
        } else {
            return response
        }
    },
    error => {
        throw new Error(error)
        // throw new Error(`请求错误: ${error}`)
    }
)

/*
 * @params {config} 参数从API传递过来
 * @params @{config} {url} 请求地址
 * @params @{config} {data} 请求数据
 */
export function get(config) {
    let obj = {
        url: config.url,
        method: \'get\',
        params: {
            ...config.data,
        }
    }
    return ajax(obj)
}

export function post(config) {
    let obj = {
        url: config.url,
        method: \'post\',
        data: {
            ...config.data,
        }
    }
    return ajax(obj)
}

export function upload(config) {
    let obj = {
        url: config.url,
        method: \'post\',
        data: config.data,
        headers: {
            \'Content-Type\': \'multipart/form-data\'
        }
    }
    return ajax(obj)
}

urls文件夹下创建对应模块的url信息

例如 urls/user.js

export default {
    userinfo: \'/user/userinfo\',
    userList: \'/user/userList\'
}

apis文件夹下创建对应模块的api函数

例如 apis/user.js

import { get, post } from \'../http.js\'
import user from \'../urls/user\'

export function getUserinfo(params) {
    return get({ url: userUrls.userinfo, params })
}

export function getUserList(params) {
    return post({ url: userUrls.userList, params })
}

页面内正常使用我们熟知的方式引入api函数去调接口获取数据

3、axios跨域配置

1) 、使用官方axios模块时的配置

export default {
    axios: {
        proxy: true,
        prefix: \'/api\', // baseURL
        credentials: true,
        retry: { retries: 3 }
    },
    proxy: {
        \'/api\': {
            target: \'http://192.168.xxx.xxx:xxxx\', // 代理地址
            changeOrigin: true,
            pathRewrite: {
                \'^/api\': \'\', //将 /api 替换掉
            }
        },
    }
}

2) 、使用官方axios模块,引入官方模块 @nuxtjs/proxy 配置

npm i @nuxtjs/proxy -D

nuxt.config.js 中配置

modules: [
    \'@nuxtjs/axios\',
    \'@nuxtjs/proxy\'
],
proxy: [
    [
        \'/api\', 
        { 
            target: \'http://localhost:3001\', // api主机
            pathRewrite: { \'^/api\' : \'/\' }
        }
    ]
]

3) 、使用外部引入的方式

配合后端部署设置nginx

三、登录状态持久化

npm i -S cookie-universal-nuxt

nuxt.config.js 中配置

modules: [
    // 登录状态持久化
    [\'cookie-universal-nuxt\', { parseJSON: true }]
],

store配置请参考本文下面的i18n部分, store/index.js

四、引入ant-design-vue组件库

npm i -S ant-design-vue
npm install babel-plugin-import --save-dev

1、按需引入配置

// nuxt.config.js
{
    build: {
        babel: {
            plugins: [
                [
                    \'import\',
                    {
                        libraryName: \'ant-design-vue\',
                        libraryDirectory: \'es\',
                        style: true
                        // 默认不使用该选项,即不导入样式 , 注意 ant-design-vue 使用 js 文件引入样式
                        // true 表示 import \'ant-design-vue/es/component/style\'
                        // \'css\' 表示 import \'ant-design-vue/es/component/style/css\'
                    }
                ]
            ]
        }
    }
}

~/plugins 文件夹创建 antd-ui.js 文件

import Vue from \'vue\'

Vue.config.productionTip = false

import { Button } from \'ant-dsign-vue\'

Vue.use(Button)

2、antd-icon 过大

不是所有的图标我们都能用到

~/plugins 文件夹创建 antd-icons.js 文件

export {
    // 需要使用到的 Icons
    InfoCircleFill,
    DownOutline,
    UpOutline,
    RightOutline,
    LeftOutline
} from \'@ant-design/icons\'
// nuxt.config.js
const CompressionPlugin = require(\'compression-webpack-plugin\')
const path = require(\'path\')

export default {
    build: {
        vendor: [\'axios\', \'ant-design-vue\'],
        // 解决less加载使用不了的问题
        loaders: {
            less: {
                javascriptEnabled: true
            }
        },
        analyze: {
            analyzerMode: \'static\'
        },
        // 使用Babel与特定的依赖关系进行转换
        transpile: [/ant-design-vue/],
        extend(config, ctx) {
            // 配置eslint
            if (ctx.isClient) {
                config.module.rules.push({
                    enforce: \'pre\',
                    test: /\\.(js|vue)$/,
                    loader: \'eslint-loader\',
                    exclude: /(node_modules)/
                })
                // ant-design-vue 的icon组件,按需引入需要的图标,文件太大
                config.resolve.alias[\'@ant-design/icons/lib/dist$\'] = path.resolve(__dirname, \'./plugins/antd-icons.js\') // 引入需要的
            }
        },
        // 打包构建优化
        plugins: [
            new CompressionPlugin({
                test: /\\.js$|\\.html$|\\.css/, // 匹配文件名
                threshold: 10240, // 对超过10kb的数据进行压缩
                deleteOriginalAssets: false // 是否删除原文件
            })
        ],
        optimization: {
            splitChunks: {
                minSize: 10000,
                maxSize: 250000
            }
        }
    }
}

注意: 这儿安装 compression-webpack-plugin 插件会报错,指定插件版本就行了

npm i --save-dev compression-webpack-plugin@6.1.1

提醒:图标使用<a-icon type="close"></a-icon>来显示

如果有组件内使用的,例如

<a-rate v-model="val">
    <a-icon #character type="star"></a-icon>
</a-rate>

五、国际化

1、引入i18n

npm  i vue-i18n --save

2、在 plugins 下创建 i18n.js

// nuxt.config.js
export default {
    plugins: [
        \'@/plugins/antd-ui\',
        { src: \'@/plugins/lazy-load\', ssr: false },
        \'@/plugins/i18n.js\',
        { src: \'~/plugins/lodash.js\', ssr: false },
        { src: \'~/plugins/moment.js\', ssr: false },
        { src: \'@/plugins/vue-swiper.js\', mode: \'client\' },
    ],
}
import Vue from \'vue\'
import VueI18n from \'vue-i18n\'
Vue.use(VueI18n)

export default ({ app, store }) => {
    // Set i18n instance on app
    // This way we can use it in middleware and pages asyncData/fetch
    app.i18n = new VueI18n({
        locale: store.state.locale,
        fallbackLocale: store.state.locale,
        messages: {
            \'en-US\': require(\'@/language/en-US.json\'),
            \'zh-CN\': require(\'@/language/zh-CN.json\')
        },
        silentTranslationWarn: true
    })

    app.i18n.path = link => {
        // 如果是默认语言,就省略
        if (app.i18n.locale === app.i18n.fallbackLocale) {
            return `/${link}`
        }
        return `/${app.i18n.locale}/${link}`
    }
}

3、在 middleware 下创建 i18n.js

// nuxt.config.js
export default {
    router: {
        middleware: [\'i18n\']
    },
}
export default function({ isHMR, app, store, route, params, error, redirect }) {
    const defaultLocale = app.i18n.fallbackLocale
    // If middleware is called from hot module replacement, ignore it
    if (isHMR) return
    // Get locale from params
    const locale = params.lang || defaultLocale

    if (store.state.locales.indexOf(locale) === -1) {
        return error({ message: \'页面未找到.\', statusCode: 404 })
    }
    // Set locale
    // store.commit(\'SET_LANG\', locale)
    app.i18n.locale = store.state.locale
    // If route is /<defaultLocale>/... -> redirect to /...
    if (locale === defaultLocale && route.fullPath.indexOf(\'/\' + defaultLocale) === 0) {
        const toReplace = \'^/\' + defaultLocale + (route.fullPath.indexOf(\'/\' + defaultLocale + \'/\') === 0 ? \'/\' : \'\')
        const re = new RegExp(toReplace)
        return redirect(route.fullPath.replace(re, \'/\'))
    }
}

4、在 store 下创建 index.js

import { getToken } from \'@/lib/token.js\'
const state = () => ({
    token: \'\',
    locales: [\'en-US\', \'zh-CN\'],
    locale: \'en-US\'
})

const mutations = {
    setToken(state, token) {
        state.token = token
    },
    SET_LANG(state, locale) {
        if (state.locales.indexOf(locale) !== -1) {
            state.locale = locale
        }
    }
}

const actions = {
    async nuxtServerInit({ commit }, { app }) {
        let token = getToken(app) || \'\'
        commit(\'setToken\', token)
        //还可以获取一些通用信息,比如个人信息,通用配置什么的
    }
}
export default {
    state,
    actions,
    mutations
}

5、在 language 下创建 en-US.jsonzh-CN.json

更多语言库,请按照规则添加

配置对应的变量属性名称,在页面用

<span>{{ $t(\'变量名\') }}</span>

对应antd-vue组件库国际化,官方推荐使用 config-provider 组件

// default.vue页面
<template>
    <a-config-provider :locale="lang">
        <div class="layout-container">
            <a-layout>
                <a-layout-header>header</a-layout-header>
                <a-layout-content><Nuxt /></a-layout-content>
                <a-layout-footer>footer</a-layout-footer>
                <a-back-top />
            </a-layout>
        </div>
    </a-config-provider>
</template>
<script>
import { mapState } from \'vuex\'
import language from \'../language/antd-lang/index\'
import moment from \'moment\'
import \'moment/locale/zh-cn\'
moment.locale(\'en\')

export default {
    data() {
        return {}
    },
    computed: {
        ...mapState({
            locale: state => state.locale
        }),
        lang: function() {
            let l = null
            switch (this.locale) {
                case \'zh-CN\':
                    l = language.zhCN
                    moment.locale(\'zh-cn\')
                    break
                case \'en-US\':
                    l = language.enUS
                    moment.locale(\'en\')
                    break
            }
            return l
        }
    }
}
</script>

language 下创建 antd-lang/index.js, 包含所有的支持语言库

// 阿拉伯
import arEG from \'~/node_modules/ant-design-vue/es/locale/ar_EG\'
// 保加利亚语
import bgBG from \'~/node_modules/ant-design-vue/es/locale/bg_BG\'
// 加泰罗尼亚语
import caES from \'~/node_modules/ant-design-vue/es/locale/ca_ES\'
// 捷克语
import csCZ from \'~/node_modules/ant-design-vue/es/locale/cs_CZ\'
// 德语
import deDE from \'~/node_modules/ant-design-vue/es/locale/de_DE\'
// 希腊语
import elGR from \'~/node_modules/ant-design-vue/es/locale/el_GR\'
// 英语
import enGB from \'~/node_modules/ant-design-vue/es/locale/en_GB\'
// 英语(美式)
import enUS from \'~/node_modules/ant-design-vue/es/locale/en_US\'
// 西班牙语
import esES from \'~/node_modules/ant-design-vue/es/locale/es_ES\'
// 爱沙尼亚语
import etEE from \'~/node_modules/ant-design-vue/es/locale/et_EE\'
// 波斯语
import faIR from \'~/node_modules/ant-design-vue/es/locale/fa_IR\'
// 芬兰语
import fiFI from \'~/node_modules/ant-design-vue/es/locale/fi_FI\'
// 法语(比利时)
import frBE from \'~/node_modules/ant-design-vue/es/locale/fr_BE\'
// 法语
import frFR from \'~/node_modules/ant-design-vue/es/locale/fr_FR\'
// 冰岛语
import isIS from \'~/node_modules/ant-design-vue/es/locale/is_IS\'
// 意大利语
import itIT from \'~/node_modules/ant-design-vue/es/locale/it_IT\'
// 日语
import jaJP from \'~/node_modules/ant-design-vue/es/locale/ja_JP\'
// 韩语/朝鲜语
import koKR from \'~/node_modules/ant-design-vue/es/locale/ko_KR\'
// 挪威
import nbNO from \'~/node_modules/ant-design-vue/es/locale/nb_NO\'
// 荷兰语(比利时)
import nlBE from \'~/node_modules/ant-design-vue/es/locale/nl_BE\'
// 荷兰语
import nlNL from \'~/node_modules/ant-design-vue/es/locale/nl_NL\'
// 波兰语
import plPL from \'~/node_modules/ant-design-vue/es/locale/pl_PL\'
// 葡萄牙语(巴西)
import ptBR from \'~/node_modules/ant-design-vue/es/locale/pt_BR\'
// 葡萄牙语
import ptPT from \'~/node_modules/ant-design-vue/es/locale/pt_PT\'
// 斯洛伐克语
import skSK from \'~/node_modules/ant-design-vue/es/locale/sk_SK\'
// 塞尔维亚
import srRS from \'~/node_modules/ant-design-vue/es/locale/sr_RS\'
// 斯洛文尼亚
import slSI from \'~/node_modules/ant-design-vue/es/locale/sl_SI\'
// 瑞典语
import svSE from \'~/node_modules/ant-design-vue/es/locale/sv_SE\'
// 泰语
import thTH from \'~/node_modules/ant-design-vue/es/locale/th_TH\'
// 土耳其语
import trTR from \'~/node_modules/ant-design-vue/es/locale/tr_TR\'
// 俄罗斯语
import ruRU from \'~/node_modules/ant-design-vue/es/locale/ru_RU\'
// 乌克兰语
import ukUA from \'~/node_modules/ant-design-vue/es/locale/uk_UA\'
// 越南语
import viVN from \'~/node_modules/ant-design-vue/es/locale/vi_VN\'
// 简体中文
import zhCN from \'~/node_modules/ant-design-vue/es/locale/zh_CN\'
// 繁体中文
import zhTW from \'~/node_modules/ant-design-vue/es/locale/zh_TW\'

export default {
    arEG,
    bgBG,
    caES,
    csCZ,
    deDE,
    elGR,
    enGB,
    enUS,
    esES,
    etEE,
    faIR,
    fiFI,
    frBE,
    frFR,
    isIS,
    itIT,
    jaJP,
    koKR,
    nbNO,
    nlBE,
    nlNL,
    plPL,
    ptBR,
    ptPT,
    skSK,
    srRS,
    slSI,
    svSE,
    thTH,
    trTR,
    ruRU,
    ukUA,
    viVN,
    zhCN,
    zhTW
}

六、scss、less样式变量全局使用

SASS: `yarn add sass-loader node-sass`
LESS: `yarn add less-loader less`
Stylus: `yarn add stylus-loader stylus`
yarn add @nuxtjs/style-resources
npm i @nuxtjs/style-resources --save-dev

配置请参考:@nuxtjs/style-resources

// nuxt.config.js
export default {
    // 下面这两个配置用一个就行了
    modules: [\'@nuxtjs/style-resources\'],
    buildModules: [\'@nuxtjs/style-resources\'],
    // 配置我们需要用到的less、scss全局变量,然后在.vue文件内直接引入
    styleResources: {
        // your settings here
        sass: [],
        scss: [\'./assets/vars/*.scss\', \'./assets/abstracts/_mixins.scss\'],
        less: [\'./assets/vars/*.less\'],
        stylus: []
    },
}

以上是关于nuxt构建项目的主要内容,如果未能解决你的问题,请参考以下文章

nuxt+vant+rem项目构建

我们如何在 Nuxt?Vuejs 项目中仅包含来自 lodash 的必需模块?

基于vue2+nuxt构建的高仿饿了么(2018版)

如何构建具有特定内容的 Nuxt

将 Google 字体系列添加到 Nuxt&Vuetify 项目

nuxt 部署上线