前端技术真是分分合合、合合分分,从前些年HTML、CSS、JavaScript混写到模块化的CommonJS、AMD、CMD,模块多了影响加载,又有了grunt、gulp、webpack等打包工具,最后发展到现在类似Vue的单文件组件,表面来看,似乎更爽了,但这样的模块化还是要靠写的人来把控了,稍有不慎,团队还真有人把.vue玩成当年的.html。

今天要说的是最近了解的一款基于Vue.js的SSR框架——Nuxt.js,用过react.js的童鞋可能都或多或少接触过Next.js,没错,这玩意和它是做同一件事的,正如前面所说,分分合合、合合分分,前后端分离好不容易在国内实施得火热起来,可百度并不怎么认你的单页App,且盲目使用之余,很多App文件过于庞大,以至于按需加载后首页渲染性能还是不理想,面对这样的问题,有SEO需求、对首屏渲染有提升要求的技术小伙伴们又在前端的小圈子里划分出了服务端,也因此有了传统型的express、koa、adonisJS等,但这并不能阻止我们前进的脚步,回到现实,当前火热的react.js、angularjs、vue.js都有了服务器端渲染方案,于是因为工作用vue.js的缘故,接触了Nuxt.js。

有点跑题,下面简单介绍下:

Nuxt.js是Vue进行SSR的一个优选开源项目,可免去繁琐的Webpack、nodejs后台服务配置等操作,方便的搭建一个支持SSR的VUE项目,据说尤大神曾去拜访过其作者,且多次在微博提及该项目。

Nuxt.js官方提供包括中文在内的五种语言文档,安装使用也十分亲民,提供了以下四种vue-cli初始化模板:

starter: Basic Nuxt.js project template

express: Nuxt.js + Express

koa: Nuxt.js + Koa

adonuxt: Nuxt.js + AdonisJS

喜欢自己动手灵活控制的童鞋也可以直接创建package.json,然后安装nuxt

npm i nuxt --S

最后在根目录创建pages的即可自动生成路由

由于Nuxt.js官方文档目前已经覆盖了大部分常用需求,这里不多拷贝,下面说一下使用中遇到的一些官方介绍不充分的地方。

1、代理

本地开发经常api跨域,常用node提供api代理服务来绕过该问题,Nuxt.js默认模板自然也提供了该能力,在官方找github找到modules目录,下面就有提供基于axios的代理模块配置,具体参考https://github.com/nuxt-community/modules/tree/master/modules/proxy

目前该模块只支持默认模板,不过express、koa等将Nuxt.js以中间件形式渲染视图的情况下,我们依然可以手动注册Nuxt.js中间件或者以纯express、koa应用形式配置proxy中间件。

2、第三方库引用

官方不屏蔽你正常的import,但有提供插件模式且推荐使用插件模式,比如我想把element-ui和nuxt.js结合做后台管理系统,有些欠缺,经过第三方博客等了解尝试,得出如下配置

第一步,plugins目录下创建element-ui.js(或你自己喜欢的名字,只需后续配置时对应插件名为文件名即可),写入:

import Vue from 'vue'
import Element from 'element-ui'

Vue.use(Element)

第二部,根目录找到或者创建nuxt.config.js配置文件,按照官方指引,配置plugins如下:

plugins: [{src: '~plugins/element-ui', ssr: true}]

ssr配置为true表示服务端渲染,因为Nuxt.js做到了前后端同构且首屏服务端渲染,后续客户端渲染,1.1.0之前element-ui不支持服务端渲染,需要配置ssr:false,且插件内指定只适用于客户端构建,只目前最新版已完美支持,无需关注此项

全局需要的样式也需要在nuxt.config.js配置

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

如果希望element-ui这样的第三方库打包进vendor文件,需要在build下的vendor项配置

vendor: [‘element-ui’]

第三部,按需加载

注释掉前面的配置,使用babel插件,在build下配置babel,安装插件babel-plugin-component

npm i babel-plugin-component -D

配置插件如下

babel: {
  plugins: [['component', [
    {
      'libraryName': 'element-ui',
      'styleLibraryName': 'theme-default'
    },
    'transform-async-to-generator',
    'transform-runtime'
  ]]],
  comments: false
}

使用时按照常规,我们根据需要导出个别组件并注册到Vue,然后正常使用即可。其他的如vux、mint-ui都可以如此配置使用,可以大大降低打包文件大小。

下面是我demo配置文件实例,贴出来以便参考

module.exports = {
  /*
   ** Headers of the page
   */
  head: {
    title: '朴人博客',
    meta: [
      {charset: 'utf-8'},
      {name: 'viewport', content: 'width=device-width, initial-scale=1'},
      {hid: 'description', name: 'description', content: '朴人博客'}
    ],
    link: [
      {rel: 'icon', type: 'image/x-icon', href: '/favicon.ico'}
    ]
  },
  /*
   ** Customize the progress-bar color
   */
  loading: false,
  /*
   ** Build configuration
   */
  css: ['element-ui/lib/theme-default/index.css'],
  plugins: [{src: '~plugins/element-ui', ssr: true}],
  modules: [
    // npm install @nuxtjs/proxy -D
    ['@nuxtjs/proxy']
  ],
  proxy: {
    '/api': {
      pathRewrite: {'^/api': '/api'},
      target: 'http://10.5.21.10:8080'
    }
  },
  build: {
    publicPath: '/resources/',
    filenames: {
      vendor: 'vendor.[hash].js',
      app: 'static.[chunkhash].js'
    },
    vendor: ['element-ui'],
    babel: {
      plugins: [['component', [
        {
          'libraryName': 'element-ui',
          'styleLibraryName': 'theme-default'
        },
        'transform-async-to-generator',
        'transform-runtime'
      ]]],
      comments: false
    },
    /*
     ** 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)/
        })
      }
    }
  }
}