Webpack使用教程(詳解)

在開始以前,咱們先來看如下Webpack官網首頁的圖片,思考已下該圖片表達的意義​css

一.Webpack基本介紹

1.1 概念的引入

思考:在網頁中,咱們常常會引入哪些常見的靜態資源html

  • JS
    • .js .jsx .coffee .ts(TypeScript 類 C# 語言)
  • CSS
    • .css .less .sass .scss
  • Images
    • .jpg .png .gif .bmp .svg
  • 字體文件(Fonts)
    • .svg .ttf .eot .woff .woff2
  • 模板文件
    • .ejs .jade .vue【這是在webpack中定義組件的方式,推薦這麼用】

問題:網頁中靜態資源多了之後存在的問題前端

  1. 網頁加載速度變慢,由於要屢次重複的發送資源請求
  2. 要處理錯綜複雜的依賴關係

如何解決上述兩個問題?vue

  1. 合併、壓縮、精靈圖、圖片的Base64編碼
  2. 可使用以前學過的requireJS、也可使用webpack能夠解決各個包之間的複雜依賴關係;

1.2 什麼是Webpack

Webpack是一個前端的項目構建工具,它是基於node.js開發出來的一個前端工具node

如何實現上述的2種解決方案?jquery

  1. 使用Gulp, 是基於 task 任務的;
  2. 使用Webpack, 是基於整個項目進行構建的;
  • 藉助於webpack這個前端自動化構建工具,能夠完美實現資源的合併、打包、壓縮、混淆等諸多功能。
  • 根據官網的圖片介紹webpack打包的過程
  • webpack官網

1.3 Webpack支持的規範

Webpack支持如下規範webpack

  1. CommonJS規範
//moduleA.js 導出
module.exports = function(){
    //...
}

//moduleB.js 導入
var moduleA = require('./moduleA')
複製代碼
  1. AMD規範(推崇依賴前置)
//moduleA.js 導入和導出
define(['jquery','./math.js'],function($,math){
    //AMD是依賴前置,將文件的依賴經過數組的形式導入,而後看成函數的參數傳遞進函數使用
    
    //經過return來實現對外接口
    return helloWorld
})
複製代碼
  1. CMD規範(推崇就近依賴,須要用到的時候再去加載模塊)git

    標準語法:define(id?,deps?,factory)github

    • 一個文件一個模塊,因此常常用文件名做爲模塊id
    • CMD推崇依賴就近,因此通常不在define的參數中寫依賴,在factory中寫
    • factory是一個函數,該函數擁有三個參數 function(require,exports,module)
      • require:一個方法,接收模塊標識,用來獲取其它模塊提供的接口
      • exports:一個對象,用來向外提供模塊接口
      • module:一個對象,存儲了與當前模塊相關聯的一些屬性和方法
define(fcuntion(require,exports,module){
       var $ = require('jquery.js')
       })
複製代碼
  1. ES6規範
  • 在ES6規範中,使用import和exports命令來導入和導出文件
//moduleA.js 導出

//...內容區

//導出函數(還能夠導出對象以及任何你想導出的數據類型)
exports.func = someFunc

//moduleB.js 導入
import func from './moduleA'
複製代碼

掘金:AMD和CMD的區別web

1.4 安裝Webpack

  1. 運行 npm i webpack -g 全局安裝Webpack,這樣就能在全局使用Webpack命令
    • 注意,若是是 webpack4.0以上的版本,須要全局安裝 Webpack-cli
  2. 在項目根目錄運行 npm i webpack --save-dev安裝到項目依賴中

1.5 命令行的使用

  • 查看Webpack版本信息
npm info webpack
複製代碼
  • 安裝指定版本的Webpack
npm install webpack@版本號
複製代碼
  • 卸載webpack
npm uninstall webpack webpack-cli -g
複製代碼

二.Webpack基本使用

2.1 Webpack基本的使用方式-實例

目標:使用Webpack打包構建列表隔行變色案例

  1. 建立基本的目錄結構

    webpack-study

    • dist
    • src
      • js
      • css
      • images
      • index.html
      • main.js
  2. 在項目目錄下面運行npm init初始化項目

  3. 使用 npm i jquery --save 安裝jquery類庫

  4. 建立main.js並書寫各行變色的代碼邏輯

    main.js
    
    //導入jquery內庫
    import $ from 'jquery'
    
    $(function(){
        $("li:odd").css('backgroundColor','red')
        $("li:even").css('backgroundColor','tomato')
    })
    複製代碼
  5. 在頁面直接引用main.js會報錯,由於瀏覽器不認識ES6的新語法import,須要使用Webpack進行處理,Webpack默認會把這種高級語法轉換爲低級瀏覽器可以識別的語法

  6. 運行 webpack 入口文件路徑 輸出文件路徑 對main.js進行處理

    webpack ./src/main.js ./dist/bundle.js
    複製代碼
  7. 在index.html中引入bundle.js代替main.js

2.2 Webpack基本配置

問題描述:

  • 每次修改文件以後,都要使用 webpack 入口文件路徑 輸出文件路徑來對文件進行處理,使用起來比較繁瑣

期待實現:

  • 直接在控制檯輸入 webpack 命令,便可自動完成文件的處理

實現方法

  • 在項目根目錄添加Webpack的配置文件 webpack.config.js
    • 在Webpack配置文件裏面配置處理的入口文件和輸出文件
    • 配置完成以後,便可在調試臺經過 webpack命令來對文件進行處理
const path = require('path')


module.exports = {
    entry:path.join(__dirname,'./src/main.js'),

    output:{
        path:path.join(__dirname,'./dist'),
        filename:'bundle.js'
    }
}
複製代碼

三.webpack-dev-server的使用

3.1 實現自動打包編譯

問題描述:每次改完代碼,都須要手動執行webpack命令打包編譯文件,比較繁瑣

目標:每次改完代碼,咱們點擊保存以後就能夠幫咱們自動打包編譯

  1. 安裝 webpack-dev-server

    • -D 將該插件的依賴寫入開發依賴中
    npm install webpack-dev-server -D
    複製代碼
  2. package.json裏面的 scripts屬性裏面添加 webpack-dev-server命令到開發環境

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server"
      },
    複製代碼
  3. 在本地安裝webpack,webpack-dev-server想要在本地項目中運行,必須在項目中也安裝 webpack

    npm install webpack -D
    複製代碼
  4. 執行 npm run dev命令便可,會有以下返回

  1. 由第四步可知,webpack-dev-server幫咱們生成的bundle.js運行於項目根目錄,這個文件並無存到物理磁盤上,而是託管到了電腦內存中,因此咱們在項目中根本看不到這個bundle.js文件,可是咱們能夠經過將index.html中的bundle.js引用路徑修改成項目根路徑,便可引用到該文件

    <script src="/bundle.js"></script>
    複製代碼
  2. 能夠認爲 webpack-dev-server 把打包好的文件,以一種虛擬的形式,託管到了項目的根目錄中,雖然咱們看不到它,可是能夠認爲和 dist,src,nodemodule,平級,有一個看不見的文件,叫作bundle.js

注意:

  • 若安裝過程當中有中斷,須要把 node-modules文件夾刪掉,從新執行 npm install下載依賴,不然會報錯
  • 最後執行npm run dev 以後,就會開始自動監聽咱們的修改,每次修改保存都會觸發自動打包編譯

3.2 額外的參數

webpack-dev-server 除了幫咱們實現自動編譯打包的功能以外,還能夠添加 額外的參數幫咱們實現更強大的功能

方式1(推薦):

  • 項目啓動後自動打開瀏覽器:--open
  • 指定項目端口號:--port 3000
  • 指定項目啓動後的主頁面:--contentBase src
  • 指定熱加載:--hot
    • 不加熱加載以前,每次修改都會生成一個新的bundle.js
    • 加了熱加載以後,每次都會在原基礎上更新bundle.js,提高 效率
//package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --port 3000 --contentBase src --hot"
  },
複製代碼

方式2(瞭解便可):

//webpack.config.js

const webpack = require('webpack')	//引入Webpack,啓用熱更新的第2步

devServer:{     //設置dev-server命令參數的第二種形式,相對麻煩一些
        open:true,
        port:3000,
        contentBase:'src',
        hot:true    // 啓用熱更新的第一步
    },
    plugins:[       //配置插件的節點,熱更新的第2步
        new webpack.HotModuleReplacementPlugin()    //new 一個熱更新的模塊對象,這是啓用熱更新的第3步
    ]
複製代碼

3.3 html-webpack-plugin插件

插件做用:

  • 在內存中,生成HTML頁面的插件
  • 將打包好的bundle.js插入頁面中去,無需咱們手動引入bundle.js

插件用法:

  1. 安裝 html-webpack-plugin插件

    npm i html-webpack-plugin -D
    複製代碼
  2. 在webpack.config.js文件中添加插件

    • 配置模版頁面,即根據該模版頁面生成內存中的頁面
    • 指定生成頁面的名稱
    //webpack.config.js
    
    const htmlWebpackPlugin = require('html-webpack-plugin')
    
    plugins:[ 
            new htmlWebpackPlugin({     //建立一個在內存中生成html頁面的插件
                template:path.join(__dirname,'./src/index.html'),//指定模版頁面,未來會根據指定的頁面路徑,去生成內存中的頁面
                filename:'index.html'
            })
        ]
    複製代碼

實際展現:

拓展:-S,-D,-g說明

npm install module_name -S 即 npm install module_name –save 寫入dependencies

npm install module_name -D 即 npm install module_name –save-dev 寫入devDependencies

npm install module_name -g 全局安裝(命令行使用)

npm install module_name 本地安裝(將安裝包放在 ./node_modules 下)

dependencies與devDependencies有什麼區別呢?

  • devDependencies 裏面的插件只用於開發環境,不用於生產環境
  • dependencies 是須要發佈到生產環境的

四.loader的使用

注意:Webpack默認只能打包處理Js類型的文件,沒法處理其它的非Js類型的文件

若是要處理非Js類型的文件,咱們須要手動安裝一些合適的第三方loader加載器

4.1 loader處理樣式表

  1. 打包處理CSS文件:安裝 style-loader css-loader

    npm i style-loader css-loader -D
    複製代碼
  2. webpack.config.js配置文件裏面新增module節點對象,在這個module對象身上,有個rules屬性數組,這個數組中,存放了全部的第三方文件愛你的匹配和處理規則

    module:{        //這個節點,用來配置全部第三方模塊加載器
            rules:[     //配置第三方模塊的匹配規則
                {test:/\.css$/,use:['style-loader','css-loader']}   //配置處理 .css文件的第三方loader規則
            ]
        }
    複製代碼
  3. 在main.js入口文件裏面引入CSS文件便可成功使用

    import './css/index.css'
    複製代碼

4.2 loader處理URL地址

問題描述:

  • 默認狀況下,Webpack沒法處理CSS文件中的URL地址,不管是圖片仍是字體庫,只要是URL,都處理不了

解決方法:

  • 經過安裝 url-loader file-loader插件來對URL進行處理

    npm i url-loader file-loader -D
    複製代碼

使用步驟

  1. 安裝 url-loader file-loader插件

  2. webpack.config.js文件裏面配置URL的處理規則

    • 參數介紹
    • limit:圖片的大小,單位是byte,若是引用的圖片大於給定的limit值,則不會被轉爲base64格式的字符串, 若是 圖片小於給定的 limit 值,則會被轉爲 base64的字符串
    • name:設置URL指定的路徑名,默認會以hash值來命名(防止重名),能夠經過以下方式經過hash值拼圖片原始名的方式來達到一樣的效果,且辨識度更高
    //URL圖片路徑的匹配規則
    {test:/\.(jpg|jepg|png|gif)$/,use:'url-loader?limit=1000&name=[hash:8]-[name].[ext]'},
    //字體圖標的匹配規則
    {test:/\.(eot|svg|woff|woff2|ttf)$/,use:'url-loader'}
    複製代碼

4.3 拓展:Webpack處理第三方文件類型的過程

  1. 先校驗文件類型,若是是js文件直接打包
  2. 若是非js文件,拿到後綴名,去webpack.config.js裏面找對應匹配規則
  3. 找到則調用規則打包,不然報錯
  4. rules的use規則數組從右到左調用,會將後面調用完畢的處理結果交給前面的規則繼續處理
  5. 調用完畢以後會將處理結果直接交給Webpack進行打包合併,最終輸出到bundle.js中去

示例:

  • 先使用css-loader插件進行處理,將處理結果交給style-loader繼續處理
module: { 
    rules: [ 
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }
    ]
  }
複製代碼

4.4 總結

  • 因爲Webpack默認只能打包處理Js類型的文件,沒法處理其它的非Js類型的文件,因此若是要處理非Js類型的文件,咱們須要手動安裝一些合適的第三方loader加載器。

  • 安裝並使用第三方加載器的方法爲如下幾步

    1. 在命令行安裝相對應的loader加載器(注意通常的loader加載器都有相對應的依賴模塊,依賴模塊一樣也須要安裝,不然程序會運行報錯)
    2. 安裝完對應的loader加載器以後,在Webpack.config.js配置文件中配置相對應的匹配規則
    //添加module對象
    //在module對象裏面添加rules數組
    //在rules數組裏面添加相對應文件的匹配規則
    
    module:{
        rules:[
            {test:/\.css$/,use:['style-loader','css-loader']}
        ]
    }
    複製代碼
    1. 若是有依賴的CSS或者其它文件,都以import命令的方式在入口js文件裏面引入
  • 完成以上步驟便可成功啓用loader加載器

五.Babel的使用

Webpack中,默認只能處理一部分ES6語法,一些更高級的ES6或者ES7語法,Webpack是處理不了的,這時候,就須要藉助第三方loader,來幫助Webpack處理這些高級的語法,當第三方loader把高級語法轉爲低級的語法以後,會把結果交給Webpack去打包到bundle.js

經過Babel,能夠幫助咱們將高級語法轉換爲低級的語法

5.1 安裝

  • 在Webpack中,能夠運行以下兩套命令,安裝兩套包,去安裝Babel相關的loader功能
    • 第一套包(相似於轉換器):cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
    • 第二套包(提供轉換關係):cnpm i bebel-preset-env babel-preset-stage-0 -D

5.2 配置

  • 在Webpack.config.js配置文件中,在module節點下的rules數組中添加一個新的匹配規則

  • 注意:

    • 在配置的babel的loader規則的時候,必定要把node_modules目錄經過exclude屬性排除掉
    • 若是不排除node_modules,則Babel會把node_modules中全部的第三方Js文件都打包編譯,這些會消耗CPU,而且致使打包速度很是慢
    • 哪怕最終babel把node_modules中的js所有轉換完了,可是,項目也沒法運行
    {test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
    複製代碼
  • 在項目的根目錄中,新建一個叫作 .babelrc 的Babel配置文件

    • 這個配置文件屬於json格式,必須複覈JSON語法規範,不能寫註釋,字符串必須使用雙引號
    • 該配置文件可參照安裝的兩套包中的插件
    • 第一套包裏面有個 babel-plugin-transfrom
    • 第二套包裏面有 babel-preset-env,babel-preset-stage-0
    {
        "presets":["env","stage-0"],
        "plugins":["transform-runtime"]
    }
    複製代碼
  • 完成以上配置,便可在項目中使用ES6語法,能夠編寫一個Class類,設置靜態屬性並打印它們來測試

六.在Webpack中使用Vue

傳統的Vue使用方式

  1. 經過 script標籤引入 vue.js文件
  2. 在body中聲明一個盒子,而且爲它設置一個id屬性
  3. 在script標籤中經過new Vue()建立一個VM實例

6.1 包的查找規則

當咱們使用 import命令導入模塊中的一個包的時候,它的查找規則是怎樣的呢

  1. 找項目目錄中有沒有 node_modules 的文件夾
  2. 在node_modules文件夾中找到對應的包名
  3. 在package.json的配置文件裏面,找到一個main屬性【main屬性指定了這個包在被加載的時候的入口文件】

接下來咱們來試着導入一個vue包,並查看它對應的入口文件

  • 安裝 npm i vue -D

  • 導入包 import Vue form 'vue'

  • 查看 node_modules/vue/package.json中的main屬性,看它的入口文件是哪一個

    "main": "dist/vue.runtime.common.js",
    複製代碼
  • 仔細回想一下,咱們平時導入的是這個文件嗎?顯然不是,咱們平時導入的是vue.js文件,那這裏爲何會不同呢?帶着這個疑問,咱們繼續

6.2 嘗試使用webpack的方式使用Vue

以下都是一些簡單的代碼模版,這裏用代碼說明,不作具體解釋

//main.js 入口文件

//此處導入的是 vue.runtime.common.js
import Vue from 'vue'

var login = {
    template:`<h1>Login success</h1>`
}

var vm = new Vue({
    el:'#app',
    data () {
        return {
            msg:'hello'
        }
    },
     components:{
         login
     }
})
複製代碼
//index.html

<body>
    <div id="app">
        <p>{{msg}}</p>
        <login></login>
    </div>
</body>
複製代碼

運行,查看結果

  • 發現報以下錯誤
  • 您正在使用Vue的僅運行時版本,其中模板編譯器不可用。 將模板預編譯爲渲染函數,或使用包含編譯器的構建。

錯誤分析

  • 以上錯誤告訴咱們,正在使用的是vue運行時版本(即咱們最開始看到的vue.runtime.common.js),編譯器不可用
  • 提供了兩種解決方法
    1. 將模版預編譯爲渲染函數(使用render函數渲染模版)
    2. 使用包含編譯器的構建(即完整的vue.js文件)

6.3 解決方法1

將模版預編譯爲渲染函數(使用render函數渲染模版)

渲染函數的使用,詳情請看這裏:Render函數的使用

經過嘗試,發現把組件寫在入口文件裏面並不能達到目標,因而,咱們抽取vue模版,經過vue文件來建立模版

  1. 建立 login.vue文件

    <template>
    	<div>
            <h1>
                這是經過 vue 文件建立的模版
        	</h1>
        </div>
    </template>
    <script>
        
    </script>
    <style>
    
    </style>
    複製代碼
  2. 安裝加載.vue文件的插件,並配置webpack.config.js

    cnpm i vue-loader vue-template-compiler -D
    複製代碼
    //webpack.config.js
    
    const vueLoaderPlugin =require('vue-loader/lib/plugin')
    
     plugins:[
            new vueLoaderPlugin()
        ],
     module:{   
         rules:[
              {test:/\.vue$/,use:'vue-loader'},       //處理.vue文件
         ]         
     },
    複製代碼
  3. 在入口文件裏面引入 login.vue,並使用render函數渲染

    import Vue from 'vue'
    
    import login from './login.vue'
    
    var vm = new Vue({
        el:'#app',
        data () {
            return {
                msg:'hello'
            }
        },
        // render:function(createElement){
        // return createElement(login)
        // },
        //簡寫
       render:c => c(login)
    })
    複製代碼
  4. 再次運行,發現運行成功

6.4 解決方法2

用包含編譯器的構建(即完整的vue.js文件)

修改原始導入的vue.runtime.common.js,將引入的包修改成vue.js

  • 有以下幾種方法均可以修改vue.js的引入路徑(推薦第三種方式)
  1. 修改node_modules中的vue的package.json文件夾的main屬性,將其指定爲vue.js
  2. 引入的時候修改引入路徑爲 import Vue from '../node_modules/vue/dist/vue.js'
  3. 仍是按照原先的引入方法 import Vue form 'vue',可是須要在 webpack.config.js文件中增長以下配置
resolve:{
        alias:{
            "vue$":"vue/dist/vue.js"
        }
    }
複製代碼
  • 完成以上設置以後,項目便可正常運行

6.5 總結

  • 在Webpack中使用 Vue
    1. 安裝 Vue 的包:npm i vue -S
    2. 因爲在Webpack中,推薦使用 .vue 這個組件 模版定義組件,因此須要安裝能解析這種文件的loader:npm i vue-loader vue-template-complier -D
    3. 在 main.js 中導入 Vue模塊:Import Vue from 'vue'
    4. 定義一個 .vue結尾的文件組件,該文件包含三個部分組成,template,script,style
    5. 在 main.js中使用 Import login from './login.vue' 命令導入這個組件
    6. 建立 vm實例,VM實例中使用渲染函數render來渲染頁面
    7. 在頁面中建立一個 id爲app的div元素,做爲VM要控制的區域

七.在Webpack中使用 Vue-Router

7.1 基本使用

  1. 安裝 vue-router依賴模塊

    npm i vue -S
    npm i vue-router -S
    複製代碼
  2. 在main.js中引入Vue 和 vue-router模塊,並顯示的調用vue-router

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    複製代碼
  3. 在src目錄下建立App.vue主頁面模版文件

    <template>
        <div>
            <h1>APP組件</h1>
        </div>
    </template>
    
    <script>
    export default {
    
    
    }
    </script>
    
    <style>
    
    </style>
    複製代碼
  4. 在 index文件中 建立一個 id 屬性等於 app的div元素

  5. src目錄下面新建文件夾,並在新建的文件夾下面建立login.vueregister.vue文件

  6. login.vueregister.vue組件應用到app主頁模板上面去

    <template>
        <div>
            <h1>APP組件</h1>
            <router-link to='/login'>Login</router-link>
            <router-link to='/register'>Register</router-link>
    
            <router-view></router-view>
        </div>
    </template>
    
    <script>
    export default {
    
    
    }
    </script>
    
    <style>
    
    </style>
    複製代碼
  7. main.js文件中配置路由,建立VM實例,掛載app

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    import app from './App.vue'
    import login from './comp1/login.vue'
    import register from './comp1/register.vue'
    
    var router = new VueRouter({
        routes:[
            {path:'/login',component:login},
            {path:'/register',component:register}
        ]
    })
    
    var vm = new Vue({
        el:'#app',
        render: c => c(app),
        router
    })
    複製代碼
  8. 完成以上配置,啓動項目便可

7.2 路由嵌套

在Webpack中使用路由的嵌套和在Vue中使用路由的嵌套基本相似

  1. 在路由基本使用的前提下,建立兩個新的組件 account,money

  2. 在login組件中添加這兩個組件的 ,並添加容器

    <template>
        <div>
            <h1>Login success</h1>
    
            <router-link to='/login/account'>Account</router-link>
            <router-link to='/login/money'>Money</router-link>
    
            <router-view></router-view>
        </div>
    </template>
    複製代碼
  3. 在路由配置中給login添加children屬性,配置account,money路由便可

    var router = new VueRouter({
        routes:[
            {path:'/login',component:login,children:[
                {path:'account',component:account},
                {path:'money',component:money},
            ]},
            {path:'/register',component:register}
        ]
    })
    複製代碼

7.3 抽離路由模塊

爲避免入口文件 main.js裏面的內容過多,咱們推薦使用抽離路由的方式,爲router單首創建一個文件夾

  • 在src目錄下建立 router.js

    import VueRouter from 'vue-router'
    
    import login from './comp1/login.vue'
    import register from './comp1/register.vue'
    import account from './comp2/account.vue'
    import money from './comp2/money.vue'
    
    var router = new VueRouter({
        routes:[
            {path:'/login',component:login,children:[
                {path:'account',component:account},
                {path:'money',component:money},
            ]},
            {path:'/register',component:register}
        ]
    })
    
    export default router
    複製代碼
  • 在main.js入口文件中,引入router.js暴露router對象,掛載到app便可

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    Vue.use(VueRouter)
    
    import app from './App.vue'
    import router from './router.js'
    
    var vm = new Vue({
        el:'#app',
        render: c => c(app),
        router
    })
    複製代碼

7.4 組件中style標籤lang屬性和scoped屬性

scoped屬性:

  • 在 .vue文件中,可經過style標籤設置組件的樣式,可是默認狀況下,設置的樣式會被渲染到全局
  • 經過在 style標籤中添加 scoped 屬性,能夠控制該樣式只在該組件裏面生效(建議使用)

lang屬性:

  • 在 .vue文件中,默認只能使用普通的 css樣式語法,若是想要使用 scss,或者 less語法樣式,須要給style標籤設置 lang屬性,而且指定具體的使用語法

    <style lang='less'>
    
    </style>
    複製代碼

...未完待續,持續更新

相關文章
相關標籤/搜索