用 cooking 搭建一个多页面易配置的 Vue 2 项目(进阶篇)

用 cooking 搭建一个多页面易配置的 Vue 2 项目(进阶篇)

通过 上一篇文章 的介绍,相信大家已经能用 cooking 配置一个较为完整的 Vue 项目。今天将通过一个多页面的例子为大家介绍 cooking 的命令行工具 —— cooking-cli,同样所需要的开发环境依旧是 Node 4+, npm 3+,同时我是在 macOS 下操作的。

搭建基础项目

现在我们需要在上一篇文章配置的项目的基础上,将它改造成支持多页面的项目,其实我们可以直接通过 cooking 的命令行工具直接生成一个 Vue 项目。首先需要全局安装 cooking-cli


npm i cooking-cli -g --registry=https://registry.npm.taobao.org

先检查下是不是使用的 npm 3+,如果不是先升级 npm 再安装。完成后可以到你的目录下执行下面指令创建一个目录名 multiple-pages 的 Vue 项目,第一次执行需要安装脚手架的依赖。

cooking create multiple-pages vue

如果没有访问较慢的话可以先配置下 npm 镜像,然后再创建项目。

cooking config registry https://registry.npm.taobao.org

接下来会让你选择一些选项,我们这次选择 Vue2 + bublé + 全局 cooking 的配置。

[?] Give your app a name: multiple-pages
[?] Give your app a description: A vue project.
[?] Private? Yes
[?] What Vue version do you what? Vue 2
[?] What ES2015+ compiler do you what to use? bublé (only use wepback 2)
[?] What way use cooking do you want? Global cooking (webpack 2)
[?] Need dev server? Yes
[?] What CSS preprocessor do you want to use? Only CSS
[?] Setup unit tests with Karma + Mocha? No
[?] git repository:
[?] author:
[?] license: ISC
[?] Continue? Yes

最后可以试试直接运行 npm run dev 看看能不能正常启动。使用全局 cooking 的好处是可以减少项目的依赖,

多页面项目分析

如果用 webpack 做 SPA 项目,通常是一个入口文件,第三方库单独打包,或者一些文件可以抽离出去通过 CDN 加载。如果换成多页面,就需要多个入口文件,同时每个页面用到的第三方库也不相同,CDN 的配置也可能不一样。那么为了方便管理,我们可以将它们写在一个配置文件里。

webpack 虽然支持配置多个 chunk,但是哪些页面引入了哪些 common chunk 都需要手动维护,而且对于新手很容易犯错。所以我打算依旧只配置一个 vendor,同时将第三方库尽可能通过 CDN 的方式加载。这样手动维护 CDN 列表比维护 chunk 清晰且容易许多。

这里的 chunk 配置我使用 cooking 默认的,它会将 node_modules 内引用到的依赖都打包到 vendor 内,同时还有一个 manifest 用来保存 webpack 的 runtime,参考 vue webapck 模板

设计配置文件

写一个名叫 app.json 的配置文件,每个入口共享公共的 CDN 也可以配置私有的 CDN,还可以配置其他基本信息。

{
  "pages": [
    {
      "entry": "home",
      "title": "首页",
      "cdn": {}
    },
    {
      "entry": "admin",
      "title": "后台",
      "cdn": {}
    }
  ],
  "basePath": "./src/pages/",
  "cdn": {
    "js": [
      "//cdn.jsdelivr.net/vue/2.0.0-rc.7/vue.min.js",
      "//cdn.jsdelivr.net/vuex/2.0.0-rc.5/vuex.min.js"
    ],
    "css": []
  },
  "externals": {
    "vue": "Vue",
    "vuex": "Vuex"
  }
}

同时我们在 src/pages 目录下创建 home 和 admin 目录。每个目录下创建一个 index.js 和 app.vue 文件。

index.js

import Vue from 'vue'
import App from './app'

new Vue({ // eslint-disable-line
  el: '#app',
  render: h => h(App)
})

app.vue

<template>
  <div>
    <h1>首页</h1>
    <p>A vue project.</p>
  </div>
</template>

<script>
  export default {
    name: 'app'
  };
</script>

配置 cooking

入口文件

接下来我们在生成的 cooking 配置文件上加工,这里我们要传入多入口的配置,从 app.json 里读取 entry 的信息,通过 basePath 拼接成文件路径。

var App = require('./app.json')

var entries = function() {
  var result = {}
  App.pages.forEach(p => {
    result[p.entry] = path.resolve(App.basePath, p.entry)
  })
  return result
}

cooking.set({
  entry: entries()
})

模板文件

所有入口的页面我们都是通过 index.tpl 模板配置,只需要将公用 CDN 和私有 CDN 合并后拼接成 HTML 插入到模板内,同时引入入口文件和 vendor,通过 html-webpack-plugin 的配置选项,可以很方便的实现我们的需求。


var App = require('./app.json')
var path = require('path')

var merge = function(a, b) {
  return {
    css: (a.css || []).concat(b.css || []),
    js: (a.js || []).concat(b.js || [])
  }
}

var templates = function() {
  return App.pages.map(p => {
    return {
      title: p.title,
      filename: p.entry + '.html',
      template: path.resolve(__dirname, 'index.tpl'),
      cdn: merge(App.cdn, p.cdn),
      chunks: ['vendor', 'manifest', p.entry]
    }
  })
}

cooking.set({
  template: templates()
})

模板文件也要改造一下。支持生成我们指定的 CDN 的 HTML 以及其他配置项。具体语法参考插件文档。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
    <% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
    <link rel="stylesheet" href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"><% } %>
  </head>
  <body>
    <div id="app"></div>
    <% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script><% } %>
  </body>
</html>

最终配置

最后我们可以优化一下配置,将生成配置的函数提取到另一个文件内,让配置信息更清晰。那么最终的配置内容如下。

var path = require('path')
var cooking = require('cooking')
var build = require('./build')

cooking.set({
  entry: build.entries(),
  dist: './dist',
  template: build.templates(),
  devServer: {
    port: 8081,
    publicPath: '/',
  },
  clean: true,
  hash: true,
  sourceMap: true,
  chunk: true,
  publicPath: '/dist/',
  extractCSS: true,
  alias: {
    'src': path.join(__dirname, 'src')
  },
  extends: ['vue2', 'buble', 'lint', 'autoprefixer'],
  externals: build.externals()
})

module.exports = cooking.resolve()

运行项目

我们直接通过 cooking 命令行启动项目。

cooking watch -p

访问 localhost:8081/home.htm 或者 localhost:8081/admin.ht 看效果。

最后我们通过 build 构建项目,最终打包文件在 dist 目录里。

cooking build -p

总结

我会把上面的配置做成脚手架,可以直接通过 cooking init pages-vue 创建项目,当然只是做了最基础的版本,还可以扩展许多内容:

  • 比如配置某些页面可以忽略全局的 CDN 文件
  • 如果熟悉 chunk,那么把 chunk 也抽离到配置文件里
  • 给入口文件加开关,不一定每次启动都打包所有入口文件
  • 开发模式不使用 CDN,只有生产环境下才使用

如果感兴趣的话欢迎来一起维护,加入更多新功能,脚手架地址


这里只是介绍了 cooking 的命令行工具最基础的用法,还有许多实用的指令以及技巧还没介绍,所以最后一篇,我将介绍一些使用上的技巧下一篇见。

---------

编辑于 2016-09-25