如何在 vue2.0 中從 0 - 1 配置 webpack4.0

前言

  • 最近掘金上關於webpack的文章像是開了掛通常,瘋狂的產出量着實讓人望洋興嘆。這不,我這麼懶的人也都來湊個熱鬧,嘿嘿(黑人頭像)!
  • 先大概說下下來到底幹神馬。本文默認你已經看過webpack官方文檔或者一些基礎的文章資料,說實話這方面的優質文章太多了,做爲一個前端菜鳥的我就不在這裏重複造輪子了,若是您還非要再去看下,得嘞,看官您這邊請:從0到1教你擼一擼webpack深刻淺出Webpackwebpack中文文檔。那咱幹啥呢,請看標題【如何在vue2.0中配置webpack4.0】,對,就是這樣的,咱們手牽手從無到有在vue2.0來配置起webpack4.0,話很少說,走起!

基礎構建

初始化環境依賴

首先咱們新建一個項目webpack-vue-demo,而後npm initnpm init -y初始化項目,會在根目錄生成一個package.json文件,打開package.json瞅一眼,除了一些基礎信息,啥也沒有,別慌,沒有就對了,這才稱得上從無到有嘛。既然是在vue中配置webpack那項目確定得要有vue環境和webpack環境,咱們這裏就都採用本地安裝(安裝依賴)的方式,經過兩行命令來搞定:css

npm i -S vue
npm i -D  vue-loader vue-style-loader vue-template-compiler
複製代碼
  • vue-loader
    官方文檔解釋是vue-loader 是一個 webpackloader,它容許你以一種名爲單文件組件 (SFCs)的格式撰寫 Vue 組件。這也就是vue中能夠.vue文件的方式寫組件的緣由。vue-loader會將.vue的組件識別成三部分templatescriptstyle而後再經過webpack配置中的其餘相關loader將其完全解析成瀏覽器可識別的htmljscss文件。
  • vue-style-loader
    用於處理vue-loader解析後的style
  • vue-template-compiler
    把 vue-loader 提取出的 HTML 模版編譯成對應的可執行的 JavaScript 代碼。
npm i -D  webpack webpack-cli
複製代碼

這裏須要注意的是從webpack4.0開始,webpackcli 被分紅了兩個包,所以咱們須要分別安裝這兩個依賴才能夠,不然在控制檯會輸出提示安裝webpack-cli,固然缺乏也是打包不成功的。html

至此,咱們的兩個必要的環境依賴安裝好了,下來咱們將項目的基礎目錄和相關基礎文件搞起來。前端

構建基礎目錄

項目根目錄下建立src文件夾,index.htmlwebpack.config.jswebpackfile.js(webpack配置文件,全部的webapck配置都在這裏進行),在src下又分別建立index.js, views文件夾等項目所需文件,具體參考效果以下:vue

webpack-vue-demo(項目根目錄)

—— src(項目源代碼目錄)
    —— index.js(項目打包入口文件)
    —— views(頁面組件)
        —— App.vue(項目根組件)
    —— assets(圖片資源目錄,存放圖片)
    —— components(公共組件目錄)
        —— child.vue(子組件)
    —— styles(公共樣式目錄,存放公共,全局等一些樣式表)
—— index.html(html模板)
—— webpack.config.js/webpackfile.js(webpack配置文件)
—— package.json(包管理文件)
複製代碼

初始化vue(實例化,掛載等)

這部分沒啥好說的,直接貼代碼吧node

<!--App.vue-->
<template> <div id="app"> <Child></Child> </div> </template>

<script>
import Child from "@/components/child"; //這裏可使用@符號,是須要在webpack配置文件裏面配置,後面會說到,先這樣寫。
export default {
  name: "App",
  data() {
    return {};
  },
  components: {
    Child
  }
};
</script>

<style scoped>
</style>
複製代碼
<!--index.js-->
import Vue from 'vue'
import App from './views/App'


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

到此,項目基礎工做已經基本落地完成,下來咱們就來專一作配置的事情(這裏項目還運行不起來,由於尚未webpack配置)。webpack

配置 webpack(version-1)

在配置以前,咱們先稍微補充點點額外的。
git

第一:咱們在啓動或者打包vue項目的時候都是使用npm run devnpm run build這樣的命令來完成的,而這樣的命令則是在package.json裏的scripts中定義的。因此那到底這是爲何呢,爲啥這裏定義後就能夠啓動webpack打包任務呢?es6

  • package.json 裏面定義的scripts字段(對象)是Npm Script的一種表現形式,也就是說Npm Script容許在package.json 文件裏面使用scripts字段定義任務,而Npm Script自己就是Npm內置的一個功能,專門用來執行任務的。因此在 package.jsonscripts對象裏定義的每個任務都是一個npm可執行的任務。這些任務每個對應一段 Shell 腳本,例如定義的 devbuild, 其底層實現原理都是經過調用 Shell 去運行腳本命令,執行 npm run build 命令等同於執行命令 node build.js。又webpack在執行打包壓縮的時候是依賴nodejs, so,應該明白了吧!執行Npm Script任務就能夠啓動webpack打包壓縮程序。

第二:配置 Webpack 的方式有兩種:github

  1. 經過一個 JavaScript 文件描述配置,例如使用 webpack.config.js 文件裏的配置;
  2. 執行 Webpack 可執行文件時經過命令行參數傳入,例如 webpack --devtool source-map

這兩種方式能夠相互搭配,例如執行 Webpack 時經過命令 webpack --config webpack.config.js 指定配置文件,再去 webpack.config.js 文件裏描述部分配置。可是只經過命令行參數傳入的選項,這種最爲少見;順勢而爲,咱們該項目中會採用兩種結合的方式。不過主要的配置都在webpack.config.js文件裏面進行。
web

下面就開始吧!

Entry

entry: 必填項,配置入口文件的名稱,爲string 類型。若是隻有一個入口文件,則能夠把它寫成靜態不變的,Webpack 執行構建的第一步將從入口開始搜尋及遞歸解析出全部入口依賴的模塊。(執行打包壓縮的入口)

<!--webpack.config.js-->
module.exports = {
    entry: "./src/index.js"
}
複製代碼

Output

output:必填項,配置如何輸出最終想要的代碼的出口,是一個對象,經常使用的屬性filename(指定導出文件名)、path(配置輸出文件存放在本地的目錄,必須是 string 類型的絕對路徑。一般經過 Node.jspath 模塊去獲取絕對路徑)

  • Tip:在配置文件中可能會很頻繁遇到path.resolve(__dirname, "xxx")的語法,這個語法是 node.jspath模塊提供的一個絕對路徑解析的方法,若是想要深刻了解,能夠去查看 node.js文檔,咱們這裏只需知道它的做用就行。固然在使用的文件中須要手動在文件頂部require進來纔可使用的。
<!--webpack.config.js-->
const path = require("path"); //node.js 裏面的path模塊,這裏用來解析絕對路徑的
module.exports = {
    entry: "./src/index.js", //指定入口文件
    output: {
        filename: "[name].[hash].js", //導出的文件名,hash值是避免文件名緩存
        path: path.resolve(__dirname, "dist") //導出的打包後文件輸出路徑(必須是絕對路徑)
    },
}
複製代碼

Loader

loader:必填項,模塊轉換器,能夠理解爲一個將非js模塊翻譯爲js模塊的具備文件轉換功能的翻譯員。由於webpack在進行模塊打包構建時只識別js模塊文件,那對於非js的類型文件須要將其進行轉換成js類型,這就是咱們項目中爲啥能夠正常使用圖片,視頻以及樣式預處理器等的緣由,它們都會對應有不一樣的loader來對其進行翻譯轉換,固然這些loader是須要配置才能夠生效的。

  • module:模塊,webpack中一切皆模塊(任何文件都看做是一個模塊)
  • rules:配置模塊的讀取和解析規則,一般用來配置Loader。其類型是一個數組,數組裏每一項都描述瞭如何去處理部分文件
  • test、include、exclude:text (指定應用當前 loader 的類型文件,這裏就是全部 .css 後綴的文件都應用css-loader來處理),include(指定去查找的目錄),exclude (排除不須要查找的目錄),通常 includeexclude二選一結合 test使用。是縮小查詢範圍的一種優化手段。
  • use: 配置應用的loader,能夠是字符串、數組、對象
  • loader:模塊解析器,能夠是字符串、數組、對象。
const path = require("path"); //node.js 裏面的path模塊,這裏用來解析絕對路徑的

module.exports = {
  entry: "./src/index.js", //指定入口文件
  output: {
    filename: "[name].[hash].js", //打包導出文件的文件名
    path: path.resolve(__dirname, "dist") //導出的打包後文件輸出路徑(必須是絕對路徑)
  },
  
  module: {
    rules: [
      {
        test: /\.css$/,//指定應用當前loader的類型文件,這裏就是全部.css後綴的文件都應用css-loader來解析
        use: [ "vue-style-loader", "css-loader"]
      },
      {
        test: /\.scss/,
        use: ["vue-style-loader""css-loader""sass-loader"]
      },
      {
        test: /\.(png|jpg|gif|svg|bmp)$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10 * 1024, //限制圖片資源大小,小於10kb的圖片會以 base64 編碼輸出,大於此限制值的會以拷貝方式(file-loader)放到 'outputPath'指定目錄下
            outputPath: "imgs/" //指定圖片資源輸出路徑,不指定默認直接放到dist目錄下,此時這裏是 dist/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目錄
      },
      {
        test: /\.vue$/,
        use: "vue-loader"
      }
    ]
  }
};
複製代碼

關於 loader,需特別注意 的是,若配置一組 loader,那麼組內的 loader 是有嚴格的執行順序的,不可顛倒。順序爲按照數組索引反方向(從尾部往頭部)依次執行,並將當前 loader 解析結果傳遞給後一個loader去解析,在最後一個 loader,返回 webpack 所預期的 JavaScript

  • vue-style-loader

    • 安裝:npm i -D vue-style-loader
    • 描述:功能相似於 style-loader,是將 css-loader 加載後的 css做爲樣式標籤動態注入到文檔中,是專門應用於 vue 模板環境下的樣式表加載器。所以若是配置了 vue-style-loader 就不須要再配置 style-loader了。
  • css-loader

    • 安裝:npm i -D css-loader
    • 描述:解釋 @import 和 url() ,會 import/require() 後再解析它們。通俗的講就是 css-loader 會找出當前 css 文件中的 @importurl() 這樣的導入語句,告訴 Webpack 依賴這些資源,而後同時將當前 css文件 解析成模塊,處理完後再把結果交給 style-loader 去處理。
  • sass-loader

    • 安裝:npm i -D sass-loader
    • 描述:sass-loader 的做用就是把 scss 源碼轉換爲 css 代碼,再把 css 代碼交給 css-loader 去處理。
  • url-loader

    • 安裝:npm i -D url-loader
    • 描述
      • 能夠把文件的內容通過 base64 編碼後注入到 JavaScript(模板中或js中引入) 或者 css(css中引入) 中去,通常用來加載解析圖片、視頻等媒體資源,但一般是處理比較小的媒體資源,例如圖片,將解析後的資源注入到代碼中去,但由於是採用 base64編碼後,所以會形成代碼文件過大,因此,一般會配合 limit屬性一塊兒使用,當超過當前 limit限制,則採用 file-loader加載解析,將資源進行拷貝。這裏還有兩個屬性值得注意,通常須要配合使用。
      • esModule:默認爲 true,表示文件加載器會生成使用 ES 模塊語法的 JS 模塊,若是關閉(false),則採用 CommonJS模塊語法來生成 JS 模塊,這裏必定要爲 false,是踩坑發現的,若是不關閉,則 採用 require方式引入的模塊資源打包後不能正常顯示。
      • outputPath:指定圖片資源輸出路徑,不指定默認直接放到dist目錄下。
  • babel-loader

    • 安裝:npm i -D @babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader
    • 描述
      • Babel 是一個 JavaScript 編譯器,能將採用 ES6ES7 甚至更高規範的代碼轉爲 ES5 規範下的代碼。爲啥轉換嘞,由於瀏覽器的支持性很差。那在項目使用過程當中 一般採用配置 loader + 插件 的形式來轉換 js 代碼,這裏的 loader也就是 babel-loader。須要注意下,由於 babel-loader 執行比較耗時,所以使用exclude去排除無需查找的目錄,好比 node_modules,不然默認會查找全部目錄下符合要求的文件。
      • babel-plugin-transform-runtimeBabel 官方提供的一個插件,做用是減小冗餘代碼。 Babel 在把 ES6 代碼轉換成 ES5 代碼時一般須要一些 ES5 寫的輔助函數來完成新語法的實現。babel-plugin-transform-runtime 的做用在於不把輔助函數內容注入到文件裏。
      • presets 屬性告訴 Babel 要轉換的源碼使用了哪些新的語法特性,一個 Presets 對一組新語法特性提供支持,多個 Presets 能夠疊加。 Presets 實際上是一組 Plugins 的集合,每個 Plugin 完成一個新語法的轉換工做
      • Babel 執行編譯的過程當中,會從項目根目錄下的 .babelrc 文件讀取配置。.babelrc 是一個 JSON 格式的文件,因此須要在項目根目錄新建一個 .babelrc文件
      <!--.babelrc-->
      {
          "presets": ["@babel/preset-env"],//設定轉碼規則
          "plugins": ["@babel/plugin-transform-runtime"] // transform-runtime 插件表示無論瀏覽器是否支持ES6,只要是ES6的語法,它都會進行轉碼成ES5
      }
      複製代碼
  • vue-loader

    • 安裝:npm i -D vue vue-loader vue-style-loader vue-template-compiler
    • Tip:該 loader 的安裝每每會結合 vue一塊兒安裝。
    • 描述:文章開頭已經描述,這裏就再也不重複說明。

至此,項目中經常使用到的 loader 就已經所有安裝及說明完畢,可能心急的小夥伴已經火燒眉毛想試試看一下效果,可是,這會還真不行,還差一個重要的配置項 插件 (plugin),因此咱們還得再往下繼續看看。

Plugin

plugin:必填項 ,插件是 webpack 的支柱功能,用於擴展 Webpack 的能力,在 webpack 的構建流程中,plugin 用於處理更多其餘的一些構建任務,只要是loader沒法實現的事,插件均可以完美的勝任。所以其地位和做用不言而喻,稱得上是webpack中最重要的配置。格式是數組,數組中的每一項都是用來行使不一樣目的的插件實例(new)。

const path = require("path"); //node.js 裏面的path模塊,這裏用來解析絕對路徑的
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自動生成html
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必須導入此插件,它負責克隆您定義的任何其餘規則,並將它們應用於.vue文件中的相應語言塊
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //分離css

module.exports = {
  ...
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      hash: true //避免緩存
    }),
    new MiniCssExtractPlugin({
      filename: "styles/[name].[hash].css", //指定分離生成的css文件名,hash爲了不緩存
    })
  ]
};

複製代碼
  • vue-loader-plugin
    • 安裝:在安裝 vue-loader的時候會生成
    • 描述:將你定義過的其它規則複製並應用到 .vue 文件裏相應語言的塊。例如,若是你有一條匹配 /\.js$/ 的規則,那麼它會應用到 .vue 文件裏的 <script> 塊。
  • html-webpack-plugin
    • 安裝:npm install -D html-webpack-plugin
    • 描述:該插件會自動生成一個 HTML5 文件, 其中包括使用 script 標籤的 body 中的全部 webpack 包,所以咱們無需擔憂打包後的全部依賴,它會幫咱們自動引入 html 模板中,例如(js,css),解放了雙手。
      • template: 這裏須要咱們提早定義好一個 html模板文件,template 屬性就是用來指定所使用的模板文件
      • filename: 是指定產出後的文件名,就是 dist目錄下的那個 html文件名。
      • hash:避免文件緩存
  • mini-css-extract-plugin
    • 安裝:npm install -D mini-css-extract-plugin
    • 描述:
      • 該插件主要做用用來分離 css 代碼,咱們的 css 代碼在通過 css-loader,style-loder解析後以字符串的形式存在於js文件中。這樣隨着項目的業務擴展,會致使當前js文件會愈來愈大,而且也會加載的很慢,因此咱們這裏使用 mini-css-extract-plugin來將每個 js 文件中的 css代碼單獨分離出來,而且支持異步、按需加載。
      • 該插件的配置方式跟其他插件略有不一樣,除了在 plugins數組裏註冊外,還須要將 style-loadervue-style-loader替換成以下的寫法:
        <!--webpack.config.js-->
        
          module: {
            rules: [
              {
               ...
                use: [
                  {
                    loader: MiniCssExtractPlugin.loader //分離css
                  },
                  "css-loader"
                ]
              },
              {
              ...
                use: [
                  {
                    loader: MiniCssExtractPlugin.loader
                  },
                  "css-loader",
                  "sass-loader"
                ]
              },
            ]
        }
        複製代碼

到這裏,項目就能夠進行打包了。只不過咱們須要在 package.jsonscript屬性中定義下任務命令就行了。

<!--package.json-->
...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development",//開發環境下打包命令
    "build": "webpack --mode production"//生產環境下打包命令
  },
複製代碼

ok,控制檯運行命令 npm run devnpm run build會發如今項目根目錄產生一個 dist文件夾,dist 文件夾下就是 webpack打包後的源代碼,咱們能夠編輯器打開 index.html瞅一眼會發現多了一個 <link><script>標籤,這就是上面提到的 html-webpack-plugin插件幫咱們完成的。而後瀏覽器運行 index.html 文件,會發現有內容,而且正是咱們開始在child.vue 組件裏定義的東西。此時就說明打包已經成功。
也許,此時的你正沉浸在喜悅中沒法自拔,但是,這並非咱們想要的結果。試想下 vue-cli中打包項目的時候是如何的一個情景,而且當咱們更改代碼的時候的熱更新又是如何的一個情景,因此,還須要優化。首先先整理下須要實現的幾個效果

  1. 本地能夠運行項目,支持代碼熱更新、熱替換
  2. 項目運行或者打包能夠看到進度條。

好了,明確需求後,咱們就來實現它。仍是先貼出代碼,再敘述實現吧。

<!--webpack.config.js-->
...
const webpack = require("webpack"); 
const ProgressBarPlugin  = require("progress-bar-webpack-plugin") //運行/打包,顯示進度條

module.exports = {
...
  devServer: {
    host: 'localhost',//開發服務器監聽的主機地址
    port: 8000, //開發服務器監聽的端口號,默認是 8080
    compress: true, //啓用壓縮
  },
  
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ProgressBarPlugin()
  ]
};

複製代碼
  • webpack-dev-server

    • 安裝:npm i -D webpack-dev-server

    • 描述:

      • 使用 DevServer會幫咱們在本地啓動一個服務,這樣咱們能夠經過在瀏覽器訪問服務地址來預覽效果,而不用每次手動去打開 index.html 文件。
      • DevServer 它提供了一些配置項能夠改變 DevServer 的默認行爲。 要配置DevServer ,除了在配置文件裏經過 devServer 傳入參數外,還能夠經過命令行參數傳入。 注意只有在經過 DevServer 去啓動 Webpack 時配置文件裏 devServer 纔會生效,由於這些參數所對應的功能都是 DevServer 提供的,Webpack 自己並不認識 devServer 配置項。
      <!--webpack.config.js-->
      module.exports = {
      ...
        devServer: {
          host: 'localhost',//開發服務器監聽的主機地址
          port: 8000, //開發服務器監聽的端口號,默認是 8080
          compress: true, //啓用壓縮
        }
      };
      複製代碼

      若是使用了命令行參數,則啓動服務時會將參數寫入devServer配置中,若是有重名,則命令行參數會覆蓋配置項屬性。

      • DevServer使用須要在package.json裏的 script屬性中配置命令:
      <!--package.json-->
      "scripts": {
          "dev": "webpack-dev-server --open",
      },
      複製代碼
      • webpack-dev-server 命令啓動服務後運行的打包文件是在 內存中,並不在 硬盤中,爲了驗證這一點,你能夠將dist文件夾刪掉,而後重啓服務,會發現並不會在項目根目錄生成 dist文件夾,何況項目仍然能夠運行。
  • HotModuleReplacementPlugin

    • 安裝:webpack內置的插件,所以無需單獨安裝。
    • 描述: 該插件是用來啓用熱替換模塊(HMR)的,啓用熱替換模塊的好處是當咱們更改了模塊文件的代碼時瀏覽器在不刷新當前頁面的狀況下更新頁面內容。其實實現有兩種方式,除了這裏的使用插件,還要就是使用命令行webpack-dev-server --hot,二者看心情任選其一便可。
  • progress-bar-webpack-plugin

    • 安裝:npm i -D progress-bar-webpack-plugin
    • 描述:該插件比較簡單,就是一個用來顯示打包進度的插件,尤爲是當項目比較大的時候,打包比較耗時,顯示進度會顯得體驗比較友好。

那麼如今,咱們再npm run dev的時候就會在本地使用服務來運行當前項目,當修改模塊中的代碼,會自動熱更新。並且還會有進度條,這樣看起來就舒服多了吧。

Resolve

resolve:可選項,格式是對象,配置 Webpack 如何尋找模塊所對應的文件。 Webpack 內置 JavaScript 模塊化語法解析功能,默認會採用模塊化標準里約定好的規則去尋找,但你也能夠根據本身的須要修改默認的規則。修改的規則就要定義在 resolve 中,如下列出來幾個比較常見的解析規則

<!--webpack.config.js-->
...
module.exports = {
    ...
    resolve: {
      extensions: [".js", ".vue", ".scss", ".css"], //後綴名自動補全,當導入文件的時候能夠省略後綴名不寫
      alias: {
        vue$: "vue/dist/vue.esm.js", //精確匹配,當import Vue from 'vue'的時候引入的是vue.esm.js這個版本庫而不是其餘版本庫
        "@": path.resolve(__dirname, "../src"), //用@代替./src路徑 因此就能夠 import xx from ' @/xx'
    }
    }
}

複製代碼

到如今,其實關於 vue2.0中配置webpack4.0的經常使用配置的知識點差很少已經說完了。那麼是時候將 webpack.config.js的總體代碼 bia出來了。

<!--webpack.config.js-->
const path = require("path"); //node.js 裏面的path模塊,這裏用來解析絕對路徑的
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自動生成html
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必須導入此插件,它負責克隆您定義的任何其餘規則,並將它們應用於.vue文件中的相應語言塊
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //分離css
const ProgressBarPlugin  = require("progress-bar-webpack-plugin") //運行/打包,顯示進度條

module.exports = {
  entry: "./src/index.js", //指定入口文件
  output: {
    filename: "[name].[hash].js", //導出的文件名
    path: path.resolve(__dirname, "dist") //導出的打包後文件輸出路徑(必須是絕對路徑)
  },
  resolve: {
    extensions: [".js", ".vue", ".scss", ".css"], //後綴名自動補全,當導入文件的時候能夠省略後綴名不寫
    alias: {
      'vue$': 'vue/dist/vue.esm.js',//精確匹配,當import Vue from 'vue'的時候引入的是vue.esm.js這個版本庫而不是其餘版本
      "@": path.resolve(__dirname, "./src") //用@代替./src路徑 因此就能夠 import xx from ' @/xx'
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/,//指定應用當前loader的類型文件,這裏就是全部.css後綴的文件都應用css-loader來處理
        use: [
          {
            loader: MiniCssExtractPlugin.loader //分離css
          },
          "css-loader"
        ]
      },
      {
        test: /\.scss/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "sass-loader"
        ]
      },
      {
        test: /\.(png|jpg|gif|svg|bmp)$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10* 1024, //限制圖片資源大小,小於10kb的圖片會以 base64 編碼輸出,大於10kb的會以拷貝方式(file-loader)放到 'outputPath'指定目錄下
            outputPath: "imgs/" //指定圖片資源輸出路徑,不指定默認直接放到dist目錄下,此時這裏是 dist/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目錄
      },
      {
        test: /\.vue$/, 
        use: "vue-loader"
      }
    ]
  },
  devServer: {
    host: 'localhost',//開發服務器監聽的主機地址
    port: 8000, //開發服務器監聽的端口號,默認是 8080
    compress: true, //啓用壓縮
    
  },
  plugins: [
    new VueLoaderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      hash: true //避免緩存
    }),
    new MiniCssExtractPlugin({
      filename: "styles/[name].[hash].css",
    }),
    new ProgressBarPlugin()
  ],
  devtool: "source-map" //能夠直接在瀏覽器控制檯source下查看項目未打包的源代碼,在出現一些錯誤的時候,
  //若是不使用source-map的時候,錯誤沒法定位到源代碼中。
  //使用了source-map之後,能夠直接定位到錯誤出現的行
};

複製代碼

同時也附上倉庫源代碼地址,有須要能夠直接 folk vue2.0中配置webpack4.0版本1源代碼地址

以上爲版本1,難道還有版本2不成(黑人問號臉)?,對,確實還有版本2。臥槽,無情!


在實際開發中咱們每每會有不一樣的環境,常見的就是開發環境和生產環境,根據不一樣的環境,每每咱們的webpack配置是有差別的,所以就須要把不一樣環境的配置從 webpack.config.js 文件中分離出來。如何分離,請繼續往下看。

webpack 分環境配置(version-2)

新建配置目錄

項目根目錄新建 build文件夾,build目錄下新建三個配置文件,分別是:webpack.base.conf.js(基礎配置文件)、webpack.dev.conf.js(開發環境配置文件)、webpack.pro.conf.js(生產環境配置文件)。

分離配置

1. webpack.base.conf.js

webpack.base.conf.js 文件放置開發環境和生產環境webpack打包時候須要的公共基礎配置項。

<!--webpack.base.conf.js->
const path = require("path"); //node.js 裏面的path模塊,用於生成絕對路徑
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必須導入此插件,它負責克隆定義的任何其餘規則,並將它們應用於.vue文件中的相應語言塊
const CopyPlugin = require("copy-webpack-plugin");//拷貝靜態文件,例如.txt,.md等文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//分離css
const ProgressBarPlugin = require("progress-bar-webpack-plugin"); //運行/打包,顯示進度條

module.exports = {
  entry: path.resolve(__dirname, "../src/index.js"), //指定入口文件
  output: {
    filename: "[name].[hash].js", //導出的文件名
    path: path.resolve(__dirname, "../dist") //導出的打包後文件輸出路徑(必須是絕對路徑)
  },
  resolve: {
    extensions: [".js", ".vue", ".scss", ".css"], //後綴名自動補全,當導入文件的時候能夠省略後綴名不寫
    alias: {
      vue$: "vue/dist/vue.esm.js", //精確匹配,當import Vue from 'vue'的時候引入的是vue.esm.js這個版本庫而不是其餘版本
      "@": path.resolve(__dirname, "../src"), //用@代替./src路徑 因此就能夠 import xx from ' @/xx'
      assets: path.resolve(__dirname, "../src/assets")
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader"
        ]
      },
      {
        test: /\.scss/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "sass-loader"
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10 * 1024, //限制圖片資源大小,小於10kb的圖片會以 base64 編碼輸出,大於的會以拷貝方式(file-loader)放到 'outputPath'指定目錄下
            outputPath: "static/imgs/" //指定圖片資源輸入路徑,不指定默認直接放到dist目錄下,此時這裏是 dist/static/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目錄
      },
      {
        test: /\.vue$/,
        use: "vue-loader"
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[hash].css"
    }),
    new ProgressBarPlugin(),
    new CopyPlugin([
      {
        from: path.resolve(__dirname, "../src/static"),
        to: "static"
      }
    ])
  ]
};
複製代碼
  • copy-webpack-plugin
    • 安裝:npm run copy-webpack-plugin -D
    • 描述:
      • 這裏新增了一個插件,copy-webpack-plugin,就是將既不是 js ,也不是 css圖片 之類的靜態文件,好比 README.md,也但願能打包到個人項目裏,而這個插件就是採用拷貝的方式來將其複製進咱們的打包目錄。
      • from:須要拷貝的靜態文件源路徑
      • to:文件拷貝後輸出的目標位置。
2. webpack.dev.conf.js

webpack.dev.conf.js 文件僅存放開發環境下 webpack打包時候/運行項目的 webpack 配置項。依然先 bia 代碼,再進行說明。

const path = require("path");
const merge = require("webpack-merge");//合併配置項的方法
const base = require("./webpack.base.conf");//基礎配置項
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自動生成html
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); //能夠識別某些類的webpack錯誤,並清除,彙總並肯定優先級。

const devWebpackConfig = merge(base, {
  mode: "development",
  devtool: "source-map",
  devServer: {
    host: "localhost", //用於配置 DevServer 服務監聽的地址,想要局域網中的其它設備訪問你本地的服務,請配置爲 0.0.0.0,默認只有本地能夠訪問
    port: 8000, //訪問端口號,默認8080,若是被佔用,會自動更換
    quiet: true, // necessary for FriendlyErrorsPlugin
    compress: true, //啓用壓縮
    open: false //自動打開瀏覽器
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(), //模塊熱替換,當更新代碼時候自動編譯,無需手動更新,通常配合webpack-dev-server 使用

    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      inject: true // true || 'head' || 'body' || false,注入資源到給定的html模板文件,若是爲true或者body,則將全部js文件都將放置在body元素的底部
    })
  ],
  devtool: "source-map" //在瀏覽器端調試方便,能夠直接看源碼
});

module.exports = new Promise(resolve => {
  const host = devWebpackConfig.devServer.host;
  const port = devWebpackConfig.devServer.port;
  devWebpackConfig.plugins.push(
    new FriendlyErrorsPlugin({
      compilationSuccessInfo: {
        messages: [`Your application is running here: http://${host}:${port}`]
      },
      onErrors: function(severity, errors) {
        // You can listen to errors transformed and prioritized by the plugin
        // severity can be 'error' or 'warning'
      }
    })
  );
  resolve(devWebpackConfig);
});

複製代碼
  • webpack-merge

    • 安裝:webpack內置,所以無需單獨安裝。
    • 描述:webpack-mergewebpack提供的一個能夠合併對象/數組並生成新的對象的方法。所以咱們這裏能夠藉助該方法,將 webpack.base.conf.js暴露的基礎配置對象合併進來。
  • friendly-errors-webpack-plugin

    • 安裝: npm i -D friendly-errors-webpack-plugin
    • 描述:
      • 能夠識別某些類的webpack錯誤,並清除,彙總並肯定優先級。簡單講,就是一個捕獲並收集打包編譯過程當中發生的錯誤,並給出提示的插件。這裏咱們用它來在編輯器控制檯顯示當前項目在瀏覽器端的訪問地址(vue-cli中那樣)
        例如:


      • 配置該插件時候須要注意兩點:

        1. 爲了引用到當前文件中配置的主機號和端口號,所以須要改寫下 module.exports 導出配置的寫法,這裏咱們使用導出 Promise 對象,具體使用請看上方的代碼。或者參考官方文檔。
        2. 除了須要在 plugins裏註冊實例,還需在 devServer 裏面添加 quiet: true,固定用法。
3. webpack.pro.conf.js

webpack.pro.conf.js 文件僅存放生產環境下 webpack打包時候的 webpack 配置項。依然先 bia 代碼,再進行說明。

const path = require("path");
const merge = require("webpack-merge"); //合併webpack options
const base = require("./webpack.base.conf");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自動生成html
const TerserPlugin = require("terser-webpack-plugin"); //壓縮js
const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");//壓縮css
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //每次打包前,先清理掉以前的打包文件

module.exports = merge(base, {
  mode: "production",
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      inject: true, // true || 'head' || 'body' || false,注入資源到給定的html模板文件,若是爲true或者body,則將全部js文件都將放置在body元素的底部
      favicon: path.resolve(__dirname,'../favicon.ico'),
      //若是將minify選項設置爲true(當webpack的模式爲「生產」時爲默認值),則將如下選項來縮小生成的HTML(壓縮html資源)
      minify: {
        removeComments: true, //移除註釋
        collapseWhitespace: true, //合併空格
        removeAttributeQuotes: true //移除屬性雙引號
      }
    }),
    new OptimizeCSSPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require("cssnano")
    }),
    new CleanWebpackPlugin()
  ]
});

複製代碼
  • terser-webpack-plugin

    • 安裝:npm i -D terser-webpack-plugin

    • 描述:

      • 該插件用來壓縮 js 代碼,使用它而捨棄 uglifyjs-webpack-plugin 插件的最大一個緣由就是支持 es6 語法,而 ``uglifyjs-webpack-plugin`不支持,對就是這麼任性。
      • 該插件的配置方式有點特別,不是註冊在 plugins中,而是在 optimization中,關於 optimization,看官方文檔的描述爲優化,是一個對象,而後對象裏面能夠手動配置重寫一些優化項和策略。感受比較高深,我就淺嘗輒止,將TerserPlugin插件相關的優化項寫進來。
      <!--webpack.pro.conf.js-->
       optimization: {
          minimize: true, //告知 webpack 使用 TerserPlugin 壓縮 打包後的js文件
          minimizer: [new TerserPlugin()], //容許經過提供一個或多個定製過的 TerserPlugin 實例,覆蓋默認壓縮工具(minimizer)。
      },
      複製代碼
  • optimize-css-assets-webpack-plugin

    • 安裝:npm i -D optimize-css-assets-webpack-plugin
    • 描述:
      • 優化/壓縮 css 的插件,使用該插件不只壓縮出來的 css 擁有很好的格式,並且壓縮過程當中採用的多種優化策略來保證 css 文件體積儘可能的小
      • assetNameRegExp:指定要壓縮優化那種類型的靜態資源文件(正則表達式)
      • cssProcessor:指定壓縮優化 css 文件時採用的那種 css 處理器,默認爲 cssnano
  • clean-webpack-plugin

    • 安裝:npm i -D clean-webpack-plugin
    • 描述:
      • 該插件用於刪除/清理構建文件夾(dist),能夠對比下該插件使用先後 dist 目錄下文件差別,會發現安裝前屢次打包後 dist 目錄下會保留每次打包生成的構建文件,那這樣就帶來一個問題,雖然咱們打包次數的增長,若不手動刪除dist會愈來愈大。這確定不是咱們想要的。所以使用該插件能夠幫咱們每一次從新打包前刪除先前的構建文件夾。
      • 該插件的引入略有點特殊 const { CleanWebpackPlugin } = require("clean-webpack-plugin");,固定用法,瞭解便可。

還記得咱們 package.json script屬性裏面的任務命令嗎?對,這裏如今得更改下就能夠起飛了。

<!--package.json-->
...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --config ./build/webpack.dev.conf.js",
    "build": "webpack --config ./build/webpack.pro.conf.js"
  },
  ...
複製代碼

npm run devnpm run build 操做起來,看看此時構建過程跟構建後的文件跟以前有啥不一樣呢? 嘿嘿嘿!。

相信能堅持看到這裏的老鐵絕對是真愛,因此若是您以爲對你有幫助或者心裏有些許波瀾,麻煩給小弟 點個贊star~下,蟹蟹!

最後附上版本2的倉庫源代碼地址,有須要能夠直接 folk vue2.0中配置webpack4.0版本2源代碼地址

後記

以上就是在 vue2.0 中從 0 - 1 配置 webpack的所有內容了,webpack4.0的東西很是之多,也很是之高深,做爲一個前端菜鳥深知須要學習和進步的空間還很大,所以,如如有 不恰當/不許確 之處,還望路過的各位大佬多多指教。不勝感激!

相關文章
相關標籤/搜索