基於 Webpack 4 搭建 Vue 開發環境

自從工做以後,就已經好久沒有寫過博客了。時間被分割得比較碎,積累了一段時間的學習成果,才寫下了這篇博客。javascript

以前有寫過 Webpack4 的文章,可是都比較偏入門,惟一的一篇實戰篇 —— 基於Webpack搭建React開發環境,也是比較簡單的,沒有涉及到 CSS 抽取,第三方庫打包等功能,這篇文章相對而言比較深刻。但因爲做者水平有限,不免存在謬誤之處,歡迎你們指正。css

還有沒入門的童鞋能夠參考我以前的文章:html

1、初始化項目

在命令行中敲入以下命令:vue

$ mkdir Webpack-Vue && cd Webpack-Vue && npm init -y

而後你就能夠在你的當前路徑下看到一個叫 Webpack-Vue 的文件夾,裏面有一個包含默認信息的 package.json 文件,打開並修改這個文件的一些內容。java

而後咱們在項目文件夾中建立如下幾個文件夾:node

  • dist
  • src、src/components
  • build

Linux 下能夠輸入一下命令進行快速建立:react

$ mkdir src src/components dist build -p

其中,dist 用於存放 Webpack 打包後的項目文件、src 用於存放你的源代碼文件、build 用於存放 Webpack 打包相關的配置文件。webpack

在 src 下,建立入口文件 index.jsgit

Linux 下建立的命令:github

$ touch ./src/index.js

在根目錄下建立 index.html 文件,內容以下:

<!DOCTYPE html>
    <html>
      <head>
        <title>Webpack Vue Demo</title>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
      </head>
      <body>
        <div id="app"></div>
      </body>
    </html>

這將用於做爲咱們應用的模板,打包的 js 文件會在 Webpack 插件的處理下插入到這個文件中。

其餘配置性文件根據你本身的喜愛來添加了,好比 .gitignore 文件等。

2、安裝 Webpack

要使用 Webpack,第一步固然是先安裝。使用如下命令進行安裝:

$ npm i webpack webpack-cli -D

而後你就能夠看到你的項目文件夾中多了一個 node_modules 文件夾,而後 package.json 文件中多了一個 devDependencies 屬性。裏面包含了安裝的依賴名稱和依賴版本,如今暫時還只有 webpackwebpack-cli

3、配置最基本的 Webpack

這一節咱們將着手配置一個具備最基本打包功能的項目,從 src/index.js 開始對項目進行打包。

爲了項目結構更加科學合理,咱們把全部的 Webpack 配置相關的文件都存放在了 build 目錄中。

進入 build 文件夾,而後建立如下幾個文件:

  • webpack.base.conf.js
  • webpack.dev.conf.js
  • webpack.prod.conf.js
  • build.js

在 Linux 中,能夠敲入以下命令快速建立:

$ cd build/ && touch webpack.base.conf.js webpack.dev.conf.js webpack.prod.conf.js build.js

其中,webpack.base.conf.js 是最基礎的打包配置,是開發環境和生產環境都要用到的配置。webpack.dev.conf.js 就是在開發環境要使用的配置。webpack.prod.conf.js 就是在生產環境要使用的配置了。build.js 是經過 Node 接口進行打包的腳本。

接下來咱們在對應的文件中寫入最基本的配置信息。

(1) webpack.base.conf.js

先寫最基本的配置信息:

const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    module.exports = {
      entry: {
        bundle: path.resolve(__dirname, '../src/index.js')
      },
      output: {
        path: path.resolve(__dirname, '../dist'),
        filename: '[name].[hash].js'
      },
      module: {
        rules: [
          
        ]
      },
      plugins: [
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, '../index.html')
        })
      ]
    };

(2) webpack.dev.conf.js

一樣寫入最基本的配置信息:

const merge = require('webpack-merge');
    const path = require('path');
    const baseConfig = require('./webpack.base.conf');
    module.exports = merge(baseConfig, {
      mode: 'development',
      devtool: 'inline-source-map',
      devServer: {
        contentBase: path.resolve(__dirname, '../dist'),
        open: true
      }
    });

(3) webpack.prod.conf.js

繼續寫入最基礎的配置:

const merge = require('webpack-merge');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const path = require('path');
    const baseConfig = require('./webpack.base.conf');
    module.exports = merge(baseConfig, {
      mode: 'production',
      devtool: 'source-map',
      module: {
        rules: []
      },
      plugins: [
        new CleanWebpackPlugin(['dist/'], {
          root: path.resolve(__dirname, '../'),
          verbose: true,
          dry: false
        })
      ]
    });

注意到咱們上面引用了兩個新的依賴,須要先進行安裝才能使用:

$ npm i webpack-merge clean-webpack-plugin webpack-dev-server html-webpack-plugin -D

(4) build.js

這個腳本用於構建生產環境,開發環境基於 webpack-dev-server 搭建,不寫腳本。

接下來,寫入咱們的打包腳本,經過 Node 調用 Webpack 進行打包。

const webpack = require('webpack');
    const config = require('./webpack.prod.conf');

    webpack(config, (err, stats) => {
      if (err || stats.hasErrors()) {
        // 在這裏處理錯誤
        console.error(err);
        return;
      }
      // 處理完成
      console.log(stats.toString({
        chunks: false,  // 使構建過程更靜默無輸出
        colors: true    // 在控制檯展現顏色
      }));
    });

這樣作的好處是能夠利用 Node 作一些其餘的事情,另外當 Webpack 配置文件不在項目文件夾根部時方便調用。

(5) npm scripts

配置 npm scripts 可以使咱們更方便的使用打包命令。

package.json 文件的 scripts 屬性中,寫入以下兩條:

"build": "node build/build.js",
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"

基本的配置寫完了,咱們測試一下打包效果,在 src/index.js 中寫入以下代碼:

console.log('index.js!');

而後在命令行中輸入:

$ npm run dev

在自動打開的網頁中,我打開控制檯,咱們能夠看到輸出了一句「index.js」,符合預期。

而後輸入構建命令進行構建:

$ npm run build

截圖以下:

img

這就表示打包成功了,可是咱們還只完成了最基本的打包功能,Vue 還不能使用,接下來咱們將這個項目變得更增強大。

4、引入一些基礎的 Loader

爲了方便開發,咱們須要引入一些 Loader,以簡化咱們的寫法以及使咱們的代碼兼容更多的環境。

這一部分能夠根據 Webpack 的文檔來寫,由於都是一些基本的東西,配置起來也不難。

(1)babel-loader

爲了使咱們的 JavaScript 代碼兼容更多環境,咱們須要使用 babel-loader。

配置方法:

首先安裝 babel-loaderbabel-preset-envbabel-core。須要注意的是,若是你的 babel-loader 是 7.x 版本的話,你的 babel-core 必須是 6.x 版本;若是你的 babel-loader 是 8.x 版本的話,你的 babel-core 必須是 7.x 版本。若是不這樣的話,Webpack 會報錯。

安裝命令以下:

$ npm i babel-loader@7 babel-core babel-preset-env -D

而後在 webpack.base.conf.jsmodule.rules 中新增以下對象:

{
      test: /\.js$/,
      use: 'babel-loader',
      exclude: /node_modules/
    }

咱們還須要添加一個配置文件(.babelrc)在根目錄下:

{
      "presets": [
        ["env", {
          "modules": false,
          "targets": {
            "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
          }
        }]
      ]
    }

這就是 babel-preset-env 的做用,幫助咱們配置 babel。咱們只須要告訴它咱們要兼容的狀況(目標運行環境),它就會自動把代碼轉換爲兼容對應環境的代碼。

以上代碼表示咱們要求代碼兼容最新兩個版本的瀏覽器,不用兼容 IE 8,另外市場份額超過 1% 的瀏覽器也必須支持。

只須要告訴 babel-preset-env 你想要兼容的環境,它就會自動轉換,是否是很爽?不再用配置那麼多了。

接下來咱們試一試,把 src/index.js 中的代碼改寫爲:

const x = 'index.js';

    const y = (x) => {
      console.log(x);
    }

    y(x);

而後使用 npm run build 進行打包,打包以後的代碼中:

var x = 'index.js';

    var y = function y(x) {
      console.log(x);
    };

    y(x);

說明咱們的代碼已經被成功地轉換了。

爲了作一個對比,未配置 babel 時,轉換結果以下:

const x = 'index.js';

    const y = (x) => {
      console.log(x);
    }

    y(x);

(2)file-loader

這個用於將字體文件、圖片文件進行模塊化。

首先安裝 file-loader

$ npm i file-loader -D

而後在 webpack.base.conf.js 中添加以下配置到 module.rules

{
      test: /\.(png|svg|jpg|gif)$/,
      use: [
        'file-loader'
      ]
    },
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      use: [
        'file-loader'
      ]
    }

固然能夠簡化配置信息,把兩個 test 正則合併到一處。

接下來咱們配置 vue-loader

(3) vue-loader

爲了使用 Vue 單文件組件,咱們須要對 .vue 文件進行處理,使用 vue-loader

首先安裝 vue-loadercss-loadervue-style-loadervue-template-compiler,後者也是必不可少的,少了會報錯。

命令:

$ npm i vue-loader css-loader vue-style-loader vue-template-compiler -D

而後咱們配置 webpack.base.conf.js,寫入如下代碼到該文件的 module.rules 屬性當中:

{
      test: /\.vue$/,
      loader: 'vue-loader'
    },
    {
      test: /\.css$/,
      use: ['vue-style-loader', 'css-loader']
    }

只有這一處配置是不行的,根據 vue-loader 官網的說明,咱們還須要配置一個插件,而後還須要配置 resolve.alias 別名,否則 Webpack 無法找到 Vue 模塊。

配置插件,首先在文件頭部引入:

const VueLoaderPlugin = require('vue-loader/lib/plugin');

而後在 plugins 數組中添加這個插件對象:

new VueLoaderPlugin(),

隨後咱們還要配置別名,將 resolve.alias 配置爲以下對象:

{
      'vue$': 'vue/dist/vue.esm.js',
      '@': path.resolve(__dirname, '../src'),
    }

這可使得 Webpack 很方便的找到 Vue,咱們在 JavaScript 文件中引入依賴的時候,也能夠方便地使用 @ 來代替 src,省去了寫文件路徑的麻煩。

咱們順便添加一個 resolve.extensions 屬性,方便咱們引入依賴或者文件的時候能夠省略後綴:

extensions: ['*', '.js', '.json', '.vue'],

extensions 屬性是一個數組。這樣配置以後,咱們在 JavaScript 文件中 import JavaScript 文件、json 文件和 Vue 單文件組件均可以省略後綴。

以上幾步都很重要,最好不要省略。

接下來咱們驗證一下 Vue 單文件組件是否可用。

安裝 Vue:

$ npm i vue --save

而後修改 index.js 文件內容以下:

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

    new Vue({
      el: '#app',
      template: '<App/>',
      components: { App }
    });

而後在同級目錄下建立一個 App.vue 文件,內容以下:

<template>
      <h1>Hello World!</h1>
    </template>

    <script>
      export default {
        name: 'App'
      }
    </script>

    <style>
      html, body {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
        font-size: 16px;
      }
    </style>

運行命令 npm run dev 就能夠看到一個大大的一級標題 —— Hello World 啦!

到這裏,咱們的項目已經可使用 Vue 單文件組件進行開發了,可是尚未完,咱們還有一些任務要作。

5、優化 CSS 代碼

這裏咱們使用 postcss 的 autoprefixer 插件爲咱們的 css 代碼自動添加前綴以適應不一樣的瀏覽器。

首先安裝依賴:

$ npm i postcss-loader autoprefixer -D

而後修改 module.rules 中的 css 配置項,修改以後以下:

{
      test: /\.css$/,
      use: ['vue-style-loader', 'css-loader', 'postcss-loader']
    }

而後在咱們項目的根目錄下新增配置文件 postcss.config.js,內容以下:

module.exports = {
      plugins: [
        require('autoprefixer')
      ]
    }

表明咱們將要使用 autoprefixer 插件。

以後咱們就能夠愉快地寫代碼了,能夠本身驗證一下是否自動添加了前綴,這裏再也不贅述。

6、開啓熱更新

Webpack 4 開啓熱更新相對容易,具體步驟以下:

修改 webpack.dev.conf.js,在 devServer 屬性中設置 hot 的值爲 true,這就表明開啓了熱更新。可是隻這樣作還不夠,須要咱們添加一個插件,繼續修改 webpack.dev.conf.js

設置其 plugins 屬性以下:

const webpack = require('webpack');
    // 在文件頭部引入 webpack 依賴
    [
      new webpack.HotModuleReplacementPlugin()
    ]

這就開啓了 css 熱更新(由於 vue-style-loader 封裝了 style-loader,熱更新開箱即用),可是 JavaScript 熱更新還不能用,每次修改代碼咱們都會刷新瀏覽器,因此咱們須要繼續配置。

爲了使得 JavaScript 模塊也能進行 HMR,咱們須要在咱們的 入口文件(index.js) 的底部添加以下代碼:

if (module.hot) {
      module.hot.accept();
    }

接下來就能夠進行 HMR 了。

7、第三方庫單獨打包

每次咱們對項目進行打包時,咱們都會把引用的第三方依賴給打包一遍,好比 Vue、Vue-Router、React 等等。可是這些庫的代碼基本都是不會變更的,咱們不必每次打包都構建一次,因此咱們最好將這些第三方庫提取出來單獨打包,這樣有利於減小打包時間。

官方插件是 DllPlugin,可是這個插件配置比較繁瑣。網上有人推薦一個比較好用的插件 —— autodll-webpack-plugin,確實很好用。

下面是它的配置方法:

首先安裝:

$ npm i autodll-webpack-plugin -D

而後在 webpack.base.conf.js 中引入:

const AutoDllPlugin = require('autodll-webpack-plugin');

而後在 plugins 屬性中添加這個插件:

new AutoDllPlugin({
      inject: true, // will inject the DLL bundle to index.html
      debug: true,
      filename: '[name]_[hash].js',
      path: './dll',
      entry: {
        vendor: ['vue', 'vue-router', 'vuex']
      }
    })

inject 爲 true,插件會自動把打包出來的第三方庫文件插入到 HTML。filename 是打包後文件的名稱。path 是打包後的路徑。entry 是入口,vendor 是你指定的名稱,數組內容就是要打包的第三方庫的名稱,不要寫全路徑,Webpack 會自動去 node_modules 中找到的。

每次打包,這個插件都會檢查註冊在 entry 中的第三方庫是否發生了變化,若是沒有變化,插件就會使用緩存中的打包文件,減小了打包的時間,這時 Hash 也不會變化。

8、提取共同代碼:

使用 splitChucksPlugin 插件,這是 Webpack 自帶的,不用安裝第三方依賴。

使用方法:

webpack.base.conf.js 的 plugins 屬性中添加以下插件對象;

new webpack.optimize.SplitChunksPlugin()

這表明你將使用默認的提取配置來提取你的公共代碼,若是你不想使用默認配置,請給插件構造函數傳入配置對象.

具體怎麼配置,請參考冷星大神的博客 —— webpack4——SplitChunksPlugin使用指南,裏面關於配置項的做用介紹得很清楚很詳細。

9、使用 stylus 預處理器

我我的比較喜歡 stylus,由於寫起來比較無拘無束,相似 Python,沒那麼多條條框框,並且用起來也不是很複雜。

引入方法:

首先下載 stylus 和 stylus-loader 依賴:

$ npm i stylus stylus-loader -D

而後在配置項 module.rules 中添加一個處理 stylus 文件的配置對象。

配置信息以下:

{
      test: /\.styl(us)$/,
      use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'stylus-loader']
    }

接下來只要你在 Vue 單文件組件的 style 標籤加上 lang='stylus',你就可使用 stylus 來寫 CSS 了。

10、抽取 CSS 到單文件

這個功能的配置方法在 Vue Loader 官網交代得很清楚了。

使用的是 mini-css-extract-plugin 插件,首先安裝:

$ npm i mini-css-extract-plugin -D

而後在配置文件頭部引入:

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

而後當你要抽取 CSS 的時候(好比生產環境打包),你就把原來配置文件中的全部 vue-style-loader 替換爲 MiniCssExtractPlugin.loader,其餘的什麼 css-loaderstylus-loader 等等都不要動。

最後,修改 plugins 選項,插入以下插件:

new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })

打包以後,你會發現全部的 CSS 代碼都被抽取到了一個單獨的 CSS 文件當中。

收穫

  • 配置要謹慎,一個錯誤就可能致使莫名其妙的報錯。
  • 學習 Webpack 要多實踐,光理論學起來比較抽象。
  • 多查 Webpack 文檔,其實不少問題裏面都交代清楚了,不要急於到網上找答案。
  • 現成的腳手架是最好的範例,好比 Vue-Cli,create-react-app。多看看它們是怎麼配置的,能夠學到一些東西。

示例代碼放在個人 GitHub 倉庫,須要的同窗能夠自取。

若有錯誤,敬請指出!

相關文章
相關標籤/搜索