Vue.js SSR Step by Step (1) - 實現簡單的client-only vue-webpack 配置

一直都以爲SSR是一個挺麻煩的事情,牽扯的知識範圍還挺大的,尤爲是用vue-cli 工具,屏蔽了許多配置的細節。
但在使用SSR,不用Nuxt.js 的時候來作SSR,仍是挺難上手的,索性好好捋一遍這方面的相關知識,總結成了一個系列的文章。做爲 SSR 文檔的一個補充,但願對你們有所幫助。javascript

目標

這篇文章的主要目的解讀一個簡單的 vue-webpack 如何搭建和每個插件的做用。完成一個 client-only的 vue-webpack 開發環境,具有如下的功能:css

  • 處理 vue 單文件組件
  • 編譯 ES6
  • 編譯 Less 或者 Sass
  • 加載圖片
  • 開發服務器
  • 熱加載
  • 定義環境變量
  • 能區分生產環境進行壓縮

對這相關配置已經很是瞭解了的同窗能夠直接關閉了。html

添加基本功能

從這一節開始會貼出一步一步實現的代碼,儘可能還原整個配置的細節。前端

建立項目文件

$ mkdir simple-webpack && cd simple-webpack
$ npm init複製代碼

而後按照下面的目錄結構新建文件。vue

.
├── index.html
├── package.json
├── src
│   ├── App.vue
│   ├── app.js
│   └── assets
└── webpack.config.js複製代碼

安裝對應依賴

須要安裝 webpack 須要的依賴有:java

  • webpack
  • vue-loader
  • babel-core
  • css-loader
  • babel-loader
  • file-loader
  • sass-loader
  • node-sass

依次安裝時,把安裝依賴保存到package.json,以便下次在不一樣的環境下使用時,能快速的安裝依賴。node

添加Vue代碼

index.htmlwebpack

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>simple - webpack</title>
</head>
<body>
    <div id="app"></div>
  <script src="/dist/build.js"></script>
</body>
</html>複製代碼

App.vuegit

<template>
  <div class="demo">
    <h1>Simple-webpack demo</h1>
    <p>這是一個簡單的 Vue demo</p>
  </div>
</template>

<script> </script>

<style> </style>複製代碼

app.jsgithub

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

new Vue({
  el: '#app',
  render: h => h(App)
})複製代碼

添加 webpack.config 配置

先寫好咱們的入口文件和輸出文件的地址和打包後的文件名。

const webpack = require('webpack')
const path = require('path')

module.exports = {
  entry: './src/app.js',
  output: {
    path: path.resolve(__dirname, './dist/'),
    filename: 'build.js'
  }
}複製代碼

添加 vue-loader

module.exports = {
  entry: './src/app.js',
  output: {
    path: path.resolve(__dirname, './dist/'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: ''
      }
    ]
  }
}複製代碼

此時運行 webpack 打包就能夠打包成一個可用的程序了,你們能夠自行打包後將文件放在靜態服務器中運行。
完成這個基本的打包,用到的webpack loader 和包有:

這個包 npm 官網上都有詳細的介紹,這裏就不贅述了,你們能夠自行去看各個loader 在上面的打包過程當中完成什麼樣工做。

爲了讓咱們編寫的代碼能在低版本的瀏覽器中使用,咱們添加 babel-loader,在打包的時候將文件中的 ES6 語法轉成 .bablerc 中配置的版本。

module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: ''
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [path.resolve(__dirname, './src')]
      }
    ]
  }複製代碼

在目錄下建立 .babelrc,配置內容以下:

{
  "presets": [
    ["env", { "modules": false }]
  ]
}複製代碼

而後須要安裝一個 babel 插件,babel-preset-env, 關於這個插件的做用具體參見 babel-preset-env: a preset that configures Babel for you

給 App.vue 中添加圖片:

<template>
  <div class="demo">
    <h1>Simple-webpack demo</h1>
    <p>這是一個簡單的 Vue demo</p>
    <img src="./assets/logo.png" alt="">
  </div>
</template>複製代碼

由於添加了圖片,再運行 webpack 打包的時候,webpack 會報錯,由於沒有對應的 loader 去加載這些二進制文件。
添加 file-loader:

module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: ''
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [path.resolve(__dirname, './src')]
      },
      {
        test: /\.(png|jpg|svg|git)$/,
        loader: 'file-loader',
        include: [path.resolve(__dirname, './src/assets')]
      }
    ]
  },複製代碼

目前咱們在單文件組件中,能夠使用 css,可是還不能使用 sass,我再添加一個對應的 sass-loader 來處理 sass 文件,由於 css/sass 是 vue-loader 在作代碼分割的時候分割出來的文本段,咱們只須要在 vue-loader 的 options 中添加對應的配置。

module: {
  rules: [
    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        'scss': 'vue-style-loader!css-loader!sass-loader',
        'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
      }
    },
    {
      test: /\.js$/,
      loader: 'babel-loader',
      include: [path.resolve(__dirname, './src')]
    },
    {
      test: /\.(png|jpg|svg|git)$/,
      loader: 'file-loader',
      options: {
        name: '[name].[ext]?[hash]'
      }
    }
  ]
},複製代碼

到目前爲止,一個具有打包編譯 Vue 項目的 webpack 環境配置已經寫好了。接下來咱們添加兩個比較重要的輔助工具 devServer 和 hot replace。

添加Dev Server 和熱更新

添加 Dev Server 的方式的方式有兩種:

  • webpack-dev-server
  • webpack-dev-middleware

兩種的使用方式和配置能夠看這篇官網介紹 開發。這裏咱們選用一種比較簡單的方式,直接使用 webpack-dev-server。
先安裝 npm install -S webpack-dev-server ,再修改 package.json 添加 npm script,代碼以下:

"scripts": {
  "test": "",
  "dev": "webpack-dev-server --open"
}複製代碼

open 參數表明服務啓動後會自動在瀏覽器中打開頁面。而後再打開 webpack.config.js 文件,添加 devServer 的相關配置。除了以上的配置還能修改 host 和 port,這裏咱們使用默認就行。添加 hot replace 也是很是簡單的,webpack 自帶了這一個 plugin,具體使用方法能夠看 模塊熱替換,新增的配置代碼以下:

module: {
 //...
},
devServer: {
  historyApiFallback: true,
  hot: true,
  noInfo: false,
  overlay: true
},
plugins: [
  new webpack.HotModuleReplacementPlugin()
]複製代碼

添加環境變量

process 是 node 中的一個模塊,咱們能夠用它的 env 變量來區分 shell 的環境變量。這樣咱們就能夠經過 npm run devnpm run build來區分咱們是開發仍是生產構建。
先修改兩個 npm script 來區分 shell 環境變量,這裏咱們藉助 cross-env npm 模塊實現自定義的環境變量。

"scripts": {
  "test": "",
  "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
  "build": "cross-env NODE_ENV=production webpack"
}複製代碼
// webpack.config.js
module.exports = {
    //...
}
console.log(process.env.NODE_ENV)
if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
}複製代碼

在 production 環境中添加了兩個插件,優化打包的代碼和壓縮 JS 代碼。第一個插件 DefinePlugin 是爲前端代碼提供與 webpack 一致的環境變量,便於咱們在業務代碼中區分不一樣的環境,Vue 框架中也要根據這個環境變量來切分開發環境和生產環境。
咱們再稍微整理一下配置,一個簡單 client-only 的 webpack 的配置就寫好了。

const webpack = require('webpack')
const path = require('path')

module.exports = {
  entry: './src/app.js',
  output: {
    path: path.resolve(__dirname, './dist/'),
    publicPath: '/dist/',
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          'scss': 'vue-style-loader!css-loader!sass-loader',
          'sass': 'vue-style-loader!css-loader!sass-loader'
        }
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [path.resolve(__dirname, './src')]
      },
      {
        test: /\.(png|jpg|svg|git)$/,
        loader: 'file-loader',
        options: {
          name: '[name].[ext]?[hash]'
        }
      }
    ]
  }
}

if (process.env.NODE_ENV === 'production') {
  module.exports.devtool = '#source-map'
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: '"production"'
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    })
  ])
} else {
  module.exports.devtool = '#eval-source-map'
  module.exports.devServer = {
    historyApiFallback: true,
    hot: true,
    noInfo: false,
    overlay: true
  }
  module.exports.plugins = (module.exports.plugins || []).concat([
    new webpack.HotModuleReplacementPlugin()    
  ])
}複製代碼

本文只是梳理打造一個簡單配置的過程,爲後面的 SSR 配置做爲基礎。webpack 的配置項很是多,而 vue-cli 中提供的 webpack 配置遠沒有那麼簡單。更進階的方式能夠閱讀參考中文章。

參考

相關文章
相關標籤/搜索