vue-cli解析

zimo發表於2017-12-26

前言

這段時間,算是空出手來寫幾篇文章了。由於很久都沒有時間整理現在所用的東西了,所以,接下來會慢慢整理出一些文件來記錄前段時間的工作和生活。

這篇文章的主題是vue-cli的理解。或許,很多人在開發vue的時候,我們會發現一個問題——只會去用,而不明白它的裡面的東西。現在的框架可以說是足夠的優秀,讓開發者不用為搭建開發環境而煩惱。但是有時候,我們還是得回到原始生活體驗一下,才能夠讓自己更上層樓,希望大家共勉。如果你喜歡我的文章,歡迎評論,歡迎Star~。歡迎關注我的github部落格

正文

首先,我們來說一下安裝的東西吧!處於有頭有尾的目的,還是幾句話草草了事。步驟如下:

  • 安裝vue-cli

    npm install vue-cli -g

  • 以webpack模版安裝目錄

    vue init webapck webpack-template

這樣之後,我們就可以使用IDE開啟目錄了。

此處註明我的vue-cli的版本2.9.2,以免之後改版之後,誤導讀者。

之後,附上自己的目錄截圖,並沒有做改動,如圖:

vue-cli-menu

首先,第一個問題,從何看起呢?當然,是從webpack.base.conf.js開始看起了。這個是dev和prod環境都會去載入的東西。然後,我們可以先從webpack.base.conf.js中會被用到的幾個檔案看起。其實,base中被用到了如下的檔案,我們可以從程式碼中看出:

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
複製程式碼

分別是:

  • path 【路徑模組】
  • build目錄中的utils.js檔案
  • config目錄中的index檔案
  • build目錄中的vue-loader.conf.js檔案

path路徑

這個模組可以看nodejs官網的介紹,其實,就是一個檔案路徑的獲取和設定等模組,學習node的時候,我們往往會看到這個模組被大量運用。

path模組提供了用於處理檔案和目錄路徑的使用工具

utils.js

我們可以到其中去看一下程式碼,其實光從名字上我們可以推斷出,它可能是為整個腳手架提供方法的。我們可以先來看一下頭部引用的資原始檔:

const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
複製程式碼

同樣的,它也引用了path模組和config目錄中的index.js檔案,之後的話是一個npm包——extract-text-webpack-plugin。這個包的話,是用來分離css和js的內容的。後續我們可以詳細瞭解一下。同時,它還引用的package.json檔案,這是一個json檔案,載入過來之後,會變成一個物件。

所以,我們需要從它的頭部依賴開始說起:

path模組我們之前提到過,這裡就不細說。我們可以來分析一下config目錄下的index.js檔案。

index.js

這個檔案中,其實有十分充足的程式碼註釋,我們也可以來深入探究一下。

從程式碼中,我們可以看到通過module.exports匯出了一個物件,其中包含兩個設定dev和build。

在dev中,設定了一些配置,程式碼如下:

modules.exports = {
	dev: {
	
	    // Paths
	    assetsSubDirectory: 'static',
	    assetsPublicPath: '/',
	    proxyTable: {},
	
	    // Various Dev Server settings
	    host: 'localhost', // can be overwritten by process.env.HOST
	    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
	    autoOpenBrowser: false,
	    errorOverlay: true,
	    notifyOnErrors: true,
	    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
	
	    // Use Eslint Loader?
	    // If true, your code will be linted during bundling and
	    // linting errors and warnings will be shown in the console.
	    useEslint: true,
	    // If true, eslint errors and warnings will also be shown in the error overlay
	    // in the browser.
	    showEslintErrorsInOverlay: false,
	
	    /**
	     * Source Maps
	     */
	
	    // https://webpack.js.org/configuration/devtool/#development
	    devtool: 'eval-source-map',
	
	    // If you have problems debugging vue-files in devtools,
	    // set this to false - it *may* help
	    // https://vue-loader.vuejs.org/en/options.html#cachebusting
	    cacheBusting: true,
	
	    // CSS Sourcemaps off by default because relative paths are "buggy"
	    // with this option, according to the CSS-Loader README
	    // (https://github.com/webpack/css-loader#sourcemaps)
	    // In our experience, they generally work as expected,
	    // just be aware of this issue when enabling this option.
	    cssSourceMap: false,
	  }
  }
複製程式碼

通過它的註釋,我們可以理解它在dev中配置了靜態路徑本地伺服器配置項EslintSource Maps等引數。如果我們需要在開發中,改動靜態資原始檔、伺服器埠等設定,可以在這個檔案中進行修改。

下面還有一個build的物件,它是在vue本地伺服器啟動時,打包的一些配置, 程式碼如下:

build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
複製程式碼

其中包括模版檔案的修改,打包完目錄之後的一些路徑設定,gzip壓縮等。明白了這些欄位的意思之後,就可以在之後的開發中,主動根據專案需求,改動目錄內容

聊完config下的index.js檔案,回到utils.js檔案中,我們可以來看幾個其中的方法,來分析它們分別起到了什麼作用。

  1. assetsPath方法

    接受一個_path引數

    返回static目錄位置拼接的路徑。

    它根據nodejs的proccess.env.NODE_ENV變數,來判斷當前執行的環境。返回不同環境下面的不同static目錄位置拼接給定的_path引數。

  2. cssLoaders方法

    接受一個options引數,引數還有的屬性:sourceMap、usePostCSS。

    同時,這裡用到了我們之前提到的extract-text-webpack-plugin外掛,來分離出js中的css程式碼,然後分別進行打包。同時,它返回一個物件,其中包含了css預編譯器(less、sass、stylus)loader生成方法等。如果你的文件明確只需要一門css語言,那麼可以稍微清楚一些語言,同時可以減少npm包的大小(畢竟這是一個令人煩躁的東西)。

  3. styleLoaders方法

    接受的options物件和上面的方法一致。該方法只是根據cssLoaders中的方法配置,生成不同loaders。然後將其返回。

  4. createNotifierCallback方法

    此處呼叫了一個模組,可以在GitHub上找到,它是一個原生的作業系統上傳送通知的nodeJS模組。用於返回腳手架錯誤的函式

一共這麼四個函式方法,在utils中被定義到。

回看到webpack.base.conf.js檔案中,我們可以直接跳過config目錄下的index.js檔案,之前已經分析過了。直接來看一下vue-loader.conf.js下的內容。

vue-loader.conf.js

這個檔案中的程式碼非常的少,我們可以直接貼上程式碼,然後來分析,其中的作用。程式碼如下:

'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
  ? config.build.productionSourceMap
  : config.dev.cssSourceMap

module.exports = {
  loaders: utils.cssLoaders({
    sourceMap: sourceMapEnabled,
    extract: isProduction
  }),
  cssSourceMap: sourceMapEnabled,
  cacheBusting: config.dev.cacheBusting,
  transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}
複製程式碼

其中,主要就是根據NODE_ENV這個變數,然後分析是否是生產環境,然後將根據不同的環境來載入,不同的環境,來判斷是否開啟了sourceMap的功能。方便之後在cssLoaders中加上sourceMap功能。然後判斷是否設定了cacheBusting屬性,它指的是快取破壞,特別是進行sourceMap debug時,設定成false是非常有幫助的。最後就是一個轉化請求的內容,video、source、img、image等的屬性進行配置。

具體的還是需要去了解vue-loader這個webpack的loader載入器。

分析了這麼多,最終回到webpack.base.conf.js檔案中

webpack.base.conf.js

其實的兩個方法,其中一個是來合併path路徑的,另一個是載入Eslint的rules的。

我們直接看後面那個函式,createLintingRule方法:

其中,載入了一個formatter,這個可以在終端中顯示eslint的規則錯誤,方便開發者直接找到相應的位置,然後修改程式碼。

之後的一個物件,就是webpack的基礎配置資訊。我們可以逐一欄位進行分析:

  • context => 執行環境的上下文,就是實際的目錄
  • entry => 入口檔案:src下的main.js檔案
  • output => 輸出內容,這內部的配置會根據不同的執行環境來進行變化
  • resolve => 其中的extensions欄位,指定檢測的檔案字尾,同時alias是用於指定別名的。在引用檔案路徑中,如果有別名的符號,會被替換成指定的路徑。
  • module => 配置了一些eslint、vue、js、圖片資源、字型圖示、檔案等載入的loader。詳細的可以去看webpack的官方網站。
  • node => 此處部分有註釋,主要是阻止一些webpack的預設注入行為,因為在vue中,已經具備了這些功能。

看完這些,你或許對webapck.base.conf.js中的內容有了一些初步的瞭解。其實,看懂它還需要你瞭解webpack這個非常有用的打包工具。

之後,我們在來回看webpack.dev.conf.js這個檔案

webpack.dev.conf.js

這個檔案中,引用了webapck-merge這npm包,它可以將兩個配置物件,進行合併。程式碼如下:

const merge = require('webpack-merge');
const devWebpackConfig = merge(baseWebpackConfig, {
	...
}
複製程式碼

這樣就合併了base中的webpack配置項。之後,我們可以來看一下dev環境中的新增了那些配置項,它們分別起到了什麼作用?

  1. 首先,在module的rules中增加了cssSourceMap的功能

  2. 然後就是devtools,通過註釋的英文翻譯,可以知道cheap-module-eval-source-map使得開發更快。

  3. 之後,就是devSever的一些配置項了。其中包塊客戶端報錯級別、埠、host等等

  4. 還有新增的plugins,我們可以來看一下實際新增的plugins(具體可以看webpack文件):

    • 定義process.env
    • HotModuleReplacementPlugin: 模組熱替換外掛
    • NameModulesPlugin: 顯示模組載入相對路徑外掛
    • NoEmitOnErrorsPlugin: 在編譯出現錯誤時,使用 NoEmitOnErrorsPlugin 來跳過輸出階段。這樣可以確保輸出資源不會包含錯誤
    • HtmlWebpackPlugin: 使用外掛生成一個指定的模版。

之後,還有一個函式,確保啟動程式時,如果埠被佔用時,會通過portfinder來發布新的埠,然後輸出執行的host字串。

webpack.prod.conf.js

這是打包到生產環境中,會被用到的檔案。我們可以看到,它相對於之前的webapck.dev.conf.js檔案少了一些外掛,多了更多的外掛。我們也可以和之前一樣,通過它新增的一些東西,來知道它到底幹了什麼!(此處的新增是相對於webpack.dev.conf.js沒有的內容)

  1. 新增了output的配置,我們可以看到它在output中新增了一些屬性,將js打包成不同的塊chunk,然後使用hash尾綴進行命名

  2. 新增了一些外掛:

    • UglifJsPlugin: 這個是用來醜化js程式碼的
    • ExtractTextplugin: 這裡新增了一些屬性,在打包的css檔案也增加了塊和hash尾綴
    • OptimizeCssplugin: 這裡是來優化css檔案的,主要就是壓縮css程式碼
    • HashedModuleIdsPlugin: 保證module的id值穩定
    • optimize: 這裡是webpack一系列優化的措施,具體可以逐一檢視官方文件
    • CopyWebPlugins: 自定義assets檔案目錄
  3. 如果沒有進行gzip壓縮,呼叫CompressionWebpackPlugin外掛進行壓縮

這樣,我們的webpack配置檔案內容基本上就全部看完了。或許,會有點蒙,還是看官方文件來的實在。

最後,還需要分析一個build.js檔案。

build.js

這個檔案是在打包的時候,會被用到的。

首先,檔案的開頭請求了check-version.js中的函式,然後確定了一下node和npm的版本。相對於較低版本的node和npm,在打包過程中,會產生警告。之後,設定環境引數,設定成生產環境,之後就是一系列打包的流程。

總結

本篇文章,主要總結了一下vue-cli生成的檔案中,其中的一些配置引數和檔案大致的作用。有不到位的地方,希望大家可以指正。同時希望我們共同進步,共勉。

如果你對我寫的有疑問,可以評論,如我寫的有錯誤,歡迎指正。你喜歡我的部落格,請給我關注Star~呦github部落格

相關文章