webpack4學習筆記---系列1

webpack到底是什麼?

本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(static module bundler)。在 webpack 處理應用程序時,它會在內部建立一個依賴圖(dependency graph),用於映射到項目須要的每一個模塊,而後將全部這些依賴生成到一個或多個bundle。css

注:webpack不是一個JS編譯器,而是模塊打包工具(並不只僅是JS模塊的打包工具,還支持CSS、圖片等文件);html

webpack支持的JS規範主要有ES Moudule、CommonJS、CMD、AMD等。
複製代碼

以上規範舉幾個例子:前端

  • ES2015 import 語句(ES6語法)
  • CommonJS require() 語句 ==> 異步引入 ,require.resolve() ==>同步方式獲取模塊ID
  • AMD define 和 require 語句,define導出方式不能在異步函數中調用
  • css/sass/less 文件中的 @import 語句。
  • 樣式(url(...))或 HTML 文件中的圖片連接(image url)

提升webpack打包速度的兩個方法:vue

(1)保持node.js的版本比較新

(2)保持webpack版本比較新
複製代碼

這是由於新版本的webpack會利用node的新特性來提升它的打包速度。node

webpack的正確安裝方式

正常webpack的安裝方式有兩種:全局安裝和本地項目安裝react

(1)使用如下命令行進行webpack全局安裝webpack

npm install webpack webpack-cli -g
複製代碼

(2)使用如下命令行進行本地項目安裝git

npm install webpack webpack-cli -D
複製代碼

以上命令至關於:github

npm install webpack webpack-cli --save-dev
複製代碼

當要選擇webpack版本時,使用npm install webpack@版本 -D進行安裝,這樣即可以在不一樣項目切換使用webpack版本。web

注意:當咱們有其餘項目須要使用到webpack3或者比較老的版本的話,若是直接使用當前的webpack命令執行打包的話會出錯,這是由於當前webpack使用的是全局安裝下的webpack命令,解決方法是卸載原先在全局安裝webpack和webpack-cli,在本地項目進行方式(2)安裝。

檢查:怎麼檢查安裝是否成功呢?

當咱們使用webpack -v時會輸出以下提示說當前全局沒有webpack,能夠安裝webpack-cli腳手架來使用

One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
 - webpack-cli (https://github.com/webpack/webpack-cli)
   The original webpack full-featured CLI.
We will use "npm" to install the CLI via "npm install -D".
Do you want to install 'webpack-cli' (yes/no):
複製代碼

此處要想使用當前項目的webpack命令,則須要加上npx,以下:

npx webpack -v
npx webpack-cli -v
複製代碼

如何簡單使用webpack的配置文件?

webpack底層已經幫咱們封裝好不少默認配置,當咱們沒有本身手動去配置時,則會使用默認配置,可是在一個比較複雜的項目下,咱們通常但願使用根據咱們需求配置好的文件來更改webpack的默認配置,簡單步驟以下:

(1)建立webpack的默認配置文件webpack.config.js

(2)修改webpack的默認配置,代碼以下:

const path = require('path');

module.exports = {
  // 配置webpack打包的入口文件
  entry: './index.js',
  // 配置webpack打包的輸出文件
  output: {
    // 配置打包完成後的文件名
    filename: 'bundle.js',
    // 配置打包完成後的文件存放目錄(絕對路徑)
    path: path.resolve(__dirname, 'bundle')
  }
}
複製代碼

(3)執行命令,進行打包

npx webpack
複製代碼

(4)當咱們有需求不想使用webpack的默認配置文件名webpack.config.js時,好比咱們能夠修改成webpackConfig.js,這時若是你執行打包命令則會報錯,由於webpack不識別你當前的配置文件,而使用原先的默認配置文件,因此咱們須要使用如下命令讓webpack以你當前配置文件爲當前配置。

npx webpack --config webpackConfig.js
複製代碼

(5)每次打包都要執行npx命令感受跟咱們之前學的不太像,能夠在npm scripts中加入對應的打包命令來代替:

"scripts": {
    "bundle": "webpack"
  }
複製代碼

接着執行以下打包命令:

npm run bunlde
複製代碼

注意:你必定有個疑問,咱們執行打包命令爲npx webpack,因此不是應該在scripts中配置成,"bundle":"npx webpack",否則會使用的全局webpack命令致使找不到?

這個是由於npm scripts的配置,由於在scripts中配置爲webpack,執行打包命令後它會先在當前項目的node_modules下查找是否有webpack,沒有的話再往上一級到全局node_modules去找。

webpack的三種使用方式

(1)在global全局下:

webpack index.js
複製代碼

(2)在當前項目文件夾:

npx webpack index.js
複製代碼

(3)使用webpack的配置文件+npm scripts中加入打包命令:

npm run bundle
複製代碼

一個疑問:原先安裝webpack-cli有什麼做用?

(1)讓咱們可以在命令行中,直接使用webpack命令

(2)在本地項目文件夾下,若是全局沒有安裝webpack,使用webpack會去全局查找webpack則報你沒安裝,而 只要你在本地項目中有裝webpack,使用npx webpack能夠找到本地webpack命令。

什麼是loader?

當咱們在打包時引入的不只僅是js文件,好比能夠是一個圖片文件:

var avator = require('./avator.jpg');
複製代碼

若是咱們還執行打包命令則會提示打包報錯,由於webpack自己在默認配置下只會打包js文件,因此當咱們要想打包圖片文件則要引入對應的loader並配置,使得webpack支持圖片打包。

webpack打包圖片須要藉助file-loader配置:

(1)首先在本地項目安裝file-loader:

npm install file-loader -D
複製代碼

(2)在webpack.config.js配置使用file-loader規則:

module: {
    rules: [{
      // 正則匹配以.jpg結尾的文件
      test: /\.jpg$/,
      // 將匹配到的文件使用file-loader進行打包
        use: {
        loader: 'file-loader'
      }
    }]
  }
複製代碼

(3)配置完成以後,使用打包命令打包:

npm run bundle
複製代碼

總之,webpack不能識別打包除JavaScript 以外的靜態資源,須要藉助各類loader來預處理文件,使之可以打包除 JavaScript 以外的任何靜態資源 。

圖片打包番外篇

在開始以前先看一下咱們目前文件的目錄結構,以下圖:

上一小節中咱們可使用webpack將圖片打包到dist目錄下了,可是若是咱們想在index.html文件下加載打包的index.js文件,index.js文件中的代碼以下:

import avator from './avator.jpg';

var root = document.getElementById("root");
var img = new Image();
img.src = avator;
root.append(img);
複製代碼

這裏index.js中建立了一個img標籤,並打包好的avator圖片賦值到img的src上,掛載到root上顯示。

接着在index.html文件中的代碼以下:

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>圖片打包番外篇</title>
</head>
<body>
	<p>圖片打包番外篇</p>
	<div id='root'></div>
	<script src='./../dist/bundle.js'></script>
</body>
</html>
複製代碼

上述代碼看着沒問題,接下來執行打包命令,沒有報錯,一切看似都很ok的,可是當咱們在瀏覽器打開index.html時看到倒是這樣的畫面,以下圖:

圖片竟然找不到,這是啥緣由啊?

img.src = avator;  //6db51315be71c2bc73d1bc8663cc1ebc.jpg
複製代碼

這是由於上面代碼img的src屬性上賦的值爲打包後圖片的名稱加擴展名,這樣子的話index.html在哪一個目錄下引入打包後的bundle.js,就如上面index.html在src目錄下引入了bunlde.js,當執行bundle.js就去src下找打包後的圖片,結果找不到。反之!若是index.html在dist目錄下的時候,恰巧打包後的圖片也在該目錄下,因此加載出來!

解決方法以下:

方式一:

將index.html移到dist打包目錄下,修改index.html中引用bundle.js的路徑爲'./bundle.js',這樣再打包一次,運行index.html圖片就顯示出來了。

方式二:

在不改變index.html位置下,直接在index.js文件中修改代碼以下:

import avator from './avator.jpg';

var root = document.getElementById("root");
var img = new Image();
img.src = "./../dist/"+avator;
console.log("./../dist/"+avator)
root.append(img);
複製代碼

這樣的話,打包成功後,圖片會被打包到dist目錄下,在img的src屬性下直接賦值dist目錄下打包好的圖片路徑就能夠找到圖片了,而後顯示在瀏覽器上。

使用Loader打包靜態資源(圖片篇)

file-loader

上面咱們用到了file-loader,可是並無比較詳細的介紹這個loader,接下來就來看看file-loader的一些經常使用配置

(1)安裝file-loader,安裝時起初沒注意直接安裝了最新版3.0.1,可是新版本並無將它所需的依賴也安裝進來,因此後面降級到2.0.0版本

npm install file-loader@2.0.0 -D
複製代碼

(2)常見的選項和placeholders結合使用

use: {
        loader: 'file-loader',
        options: {
          // placeholders 佔位符
          name: '[name]_[hash].[ext]',
          outputPath: 'images/'
        }
      }
複製代碼

選項:

name:配置自定義文件名

outputPath:配置資源的輸出目錄

emitFile:只返回 public URL 但不會生成文件 ,默認值爲true生成,false不生成
複製代碼

placeholders:佔位符

[name]:資源的基本名稱

[hash]: 配置文件名的加密規則(默認MD5加密)

[ext]:資源的擴展名

[path]:資源相對於context的路徑
複製代碼

url-loader

url-loader跟file-loader很像,基本差很少,基本配置以下:

(1)安裝

npm install url-loader -D
複製代碼

(2)快速使用

use: {
        loader: 'url-loader',
        options: {
          // placeholders 佔位符
          name: '[name]_[hash].[ext]',
          outputPath: 'images/',
          // 20KB
          limit: 20480
        }
      }
複製代碼

選項:

limit:單位爲Byte,當超過這個大小限制的話就會生成文件,不然直接以base64格式嵌入url中

fallback:當文件超過limit限制時,使用對應的loader處理(默認是file-loader)
複製代碼

url-loader與file-loader的區別

使用url-loader適用於圖片文件比較小(幾KB的那種),這樣的話能夠直接嵌入到url中,直接在瀏覽器js腳本運行時就加載,不用發送請求,可是若是圖片文件過大的話,腳本加載過長,首屏顯示就好久。

使用file-loader適用於圖片文件比較大一點的,能夠解決文件引用路徑的問題 ,打包後生成對應的圖片文件,在打開html在瀏覽器運行時發送一個請求,若是圖片較多,會發不少http請求,會下降頁面性能 。

使用Loader打包靜態資源(樣式篇)

基本的樣式打包過程

webpack支持打包的靜態資源不只是圖片等文件,還能夠是CSS、Less、Scss等樣式文件,這時候就須要藉助style-loader、css-loader、sass-loader來支持webpack打包,簡單的例子以下:

(1)在src目錄下建立index.scss,編寫以下的sass樣式:

body {
    .avator {
      width: 150px;
      height: 150px;
      transform: translate(100, 100);
    }
  }
複製代碼

(2)在src目錄下的index.js導入scss的樣式並將class添加到對應圖片的dom上,代碼以下:

import avator from './avator.jpg';
import './index.scss'

var root = document.getElementById("root");
var img = new Image();
img.src = avator;
// 往img上添加avatorclass
img.classList.add('avator');
root.append(img);
複製代碼

(3)在webpack.config.js文件中添加以下配置:

{
      test: /\.scss$/,
      use: [
        // 從下到上執行
        'style-loader',
        'css-loader',
        'sass-loader',
        'postcss-loader'
      ]
    }
複製代碼

注意:這裏的loader是從下到上執行的,若是寫成一行的話是從右到左執行

(4)在sass文件的樣式中咱們用到了transform,這個樣式屬性要支持各類瀏覽器的話要添加對應的瀏覽器廠商前綴,好比-webkit-等,這時咱們能夠藉助webpack的postcss-loader來給咱們自動添加廠商前綴,可是postcss-loader還須要建立本身的配置文件postcss.config.js而且加入autoprefixer插件,代碼以下:

  • 安裝style-loader、css-loader、sass-loader、postcss-loader、node-sass、autoprefixer:

    npm install -D style-loader css-loader sass-loader postcss-loader node-sass autoprefixer
    複製代碼
  • 在根目錄下建立postcss.config.js文件並加入以下代碼:

    module.exports = {
      plugins: [
        // 導入插件
        require('autoprefixer')
      ]
    }
    複製代碼

(5)刪除dist下的images文件夾和bundle.js,執行打包命令完成打包,打開html文件在瀏覽器運行選中對應的圖片元素能夠看到上面掛載了avator的class,而且在transform邊上還添加了廠商前綴。

執行的大概流程

  1. 執行打包命令
  2. webpack匹配到scss樣式文件
  3. 藉助sass-loader打包
  4. 打包好的scss樣式轉給css-loader轉譯
  5. 轉好的樣式交給postcss-loader並藉助autoprefixer插件自動添加相應的廠商前綴
  6. 添加好前綴的樣式轉給style-loader掛載到dom上的style裏

嵌套scss樣式問題

咱們可能在scss樣式文件中又導入另一個scss樣式文件,這樣子的話若是按原先的執行順序來執行,只能將第一個scss文件進行處理轉譯,另一個沒轉譯,即postcss-loader和sass-loader只執行一次,解決方法就是讓這兩個loader再執行一次。

相關文件代碼修改以下:

(1)在src目錄下建立一個avator.scss文件,編寫代碼以下:

body {
    .avator {
      width: 220px;
      height: 150px;
    }
  }
複製代碼

(2)在index.scss中導入avator.scss:

@import './avator.scss';

body {
  .avator {
    transform: translate(100px, 100px);
  }
}
複製代碼

(3)webpack.config.js中須要修改爲以下代碼配置:

{
      test: /\.scss$/,
      use: [
        // 從下到上執行
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            // 讓匹配到的scss樣式文件都去走如下兩個loader
            // 用於配置「css-loader 做用於 @import 的資源以前」有多少個 loader
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }
複製代碼

如何使用css的模塊化?

(1)首先咱們在前面的基礎上封裝一個createAvator.js,做用是建立頭像,createAvator.js代碼以下:

import avator from './avator.jpg';

export default function () {
  var root = document.getElementById("root");
  var img = new Image();
  img.src = avator;
  img.classList.add('avator');
  root.append(img);
}
複製代碼

(2)在index.js中引入createAvator並調用:

import avator from './avator.jpg';
import createAvator from './createAvator';
import './index.scss';

// 調用建立頭像
createAvator();

var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add('avator');
root.append(img);
複製代碼

這時執行打包命令,運行index.html能夠看到建立的兩個圖片頭像都引用到了index.scss中的樣式,index.scss中的樣式就成了全局的樣式了,如何解決這個問題,讓css樣式模塊化?

(3)要讓scss樣式支持css module,則須要在webpack.config.js中的css-loader中配置參數module爲true:

{
      test: /\.scss$/,  
      use: [
        // 從下到上執行
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2,
            // 設置css-loader支持css 的modules
            modules:  true
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }
複製代碼

(4)修改index.js中引入index.scss的方式,使用模塊化的方式引入,代碼以下:

import avator from './avator.jpg';
import createAvator from './createAvator';
import style from './index.scss';

createAvator();

var root = document.getElementById("root");
var img = new Image();
img.src = avator;
img.classList.add(style.avator);
root.append(img);
複製代碼

(5)打包運行index.html能夠看到兩張圖片頭像顯示不一樣的樣式,使用createAvator建立的頭像沒有使用index.scss的樣式,若是要想讓它也使用index.scss的樣式則須要在createAvator.js中模塊化導入index.scss並使用,代碼以下:

import avator from './avator.jpg';
// 模塊化引入index.scss,調用的時候才引用樣式
import style from './index.scss';

export default function () {
  var root = document.getElementById("root");
  var img = new Image();
  img.src = avator;
  // 使img引用style中的avator樣式
  img.classList.add(style.avator);
  root.append(img);
}
複製代碼

webpack如何打包字體文件?

在實際項目應用中咱們可能須要用到字體的樣式文件,一樣webpack也支持打包咱們項目所需的字體樣式文件,具體步驟以下:

(1)首先到iconfont阿里圖標矢量庫中添加幾個圖標到項目中,再下載對應的字體樣式文件到本地

(2)在src目錄下建立font文件夾,從下載下來的字體樣式文件取以eot、svg、ttf、woff結尾的文件到font文件夾

(3)在index.scss中粘貼iconfot.css中的內容,修改引入路徑,代碼以下:

@font-face {
  font-family: "iconfont";
  src: url('./font/iconfont.eot?t=1543245201565'); /* IE9*/
  src: url('./font/iconfont.eot?t=1543245201565#iefix') format('embedded-opentype'), /* IE6-IE8 */
 // 此處去掉了base64的一段代碼
  url('./font/iconfont.ttf?t=1543245201565') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
  url('./font/iconfont.svg?t=1543245201565#iconfont') format('svg'); /* iOS 4.1- */
}
複製代碼

(4)在index.js中導入index.scss並建立對應的字體div,代碼以下:

var root = document.getElementById('root');
import './index.scss';
// 這裏的class必須是iconfont 圖標的class名
root.innerHTML = '<div class="iconfont icon-changjingguanli"></div>';
複製代碼

(5)在webpack.config.js中添加處理eot、svg、ttf結尾的文件打包的配置,代碼以下:

{
      test: /\.(eot|svg|ttf)$/,
      use: {
        loader: 'file-loader'
      }
    }
複製代碼

(6)打包運行index.html能夠看到字體顯示出來了

使用plugins讓打包更快捷

html-webpack-plugin--自動建立Html

在咱們原先打包時,每次都要刪掉dist目錄下的除index.html,不能直接刪除整個dist,那咱們能不能在每次打包以前直接將dist目錄都直接刪除,打包完成後自動生成符合咱們配置的index.html文件呢?

這就須要藉助webpack的html-webpack-plugin了,基本使用步驟以下:

(1)安裝html-webpack-plugin

npm install html-webpack-plugin -D
複製代碼

(2)在webpack.config.js文件中引入html-webpack-plugin:

const HtmlWebPackPlugin = require('html-webpack-plugin');
複製代碼

(3)在webpack.config.js中添加配置:

plugins: [
    // 建立插件實例,添加各項配置
    new HtmlWebPackPlugin({
     // 根據index.html模板建立dist下的index.html
      template: 'src/index.html'
    })
  ]
複製代碼

注意:在咱們直接刪除dist整個目錄文件夾時,webpack打包完成後悔自動添加index.html並把打包好的bundle.js引入到script標籤之中。

plugin的本質就像vue或者react的生命週期函數同樣,能夠在webpack運行到某個時刻的時候,自動幫你作一些事。

clean-webpack-plugin--打包前自動刪除文件

咱們在上面一些操做中,每次都在打包前把dist下的文件手動刪除,有沒有好的工具能夠幫咱們解決打包前自動刪除dist文件夾及其底下全部文件?

答案確定是有的,須要藉助webpack第三方plugin即clean-webpack-plugin,具體使用步驟以下:

(1)安裝clean-webpack-plugin:

npm install clean-webpack-plugin -D
複製代碼

(2)在webpack.config.js文件中引入clean-webpack-plugin:

const CleanWebpackPlugin = require('clean-webpack-plugin');
複製代碼

(3)在webpack.config.js文件中配置plugins:

plugins: [
    // 建立插件實例,添加各項配置
    new HtmlWebPackPlugin({
      template: 'src/index.html'
    }),
     // 建立實例並傳入要刪除的文件夾
    new CleanWebpackPlugin(['dist'])
  ]
複製代碼

對於SourceMap的幾個理解

對於SourceMap是什麼,咱們能夠先作一個小實驗來引出SourceMap,大概步驟以下:

(1)在src目錄下將index.js代碼所有去掉,添加一行代碼:

consles.log("hello world");  // 這裏故意將console打錯
複製代碼

(2)在webpack.config.js中mode設置爲development 會自動打開sourceMap,所以咱們進行手動關閉:

// 手動將sourceMap關閉
  devtool: 'none',
複製代碼

(3)執行打包命令,運行index.html打開控制檯會報打包後的main.js的第96行代碼出錯,咱們點擊main.js就會進入到打包後的main.js中排錯,可是在實際中就算修改了main.js中代碼,再次打包仍是錯的,這是由於咱們只在打包好的代碼修改,並無在源文件修改,所以咱們但願控制檯報錯的時候給咱們提示的是源文件的報錯信息,這時就要藉助SourcMap的功能:

// 打開sourceMap功能
 devtool: 'source-map',
複製代碼

(4)再次執行打包,控制檯能夠看到報錯信息是在源文件的index.js中第一行console拼錯了。

sourceMap就是創建起打包以後報錯的代碼與源文件代碼之間的映射關係,主要在devtool裏面進行配置,配置參數很是多,通常只用到比較常見的幾個:
複製代碼
  • source-map:會生成.map文件用於表示與源代碼的映射關係,拖慢打包速度
  • inline-source-map:再也不生成.map文件而是將映射關係以base64形式存在打包後的文件中的data url中
  • cheap-inline-source-map:只關心源代碼的報錯,loader之中的報錯無論,再也不提示咱們具體哪行哪列報錯,而是隻精確到行,打包速度比較快
  • cheap-module-source-map:不只源代碼報錯要管,還要管loader等之中的報錯
  • eval:在打包後的文件最後一行輸出簡短的報錯信息,速度很快

如上,devtool中的參數能夠進行疊加使用,通常這樣規定:

在development模式中,devtool使用cheap-module-eval-source-map

在production模式中,devtool使用cheap-module-source-map

使用webapckDevServer提高開發效率

在咱們使用webpack打包的時候,每次修改源代碼文件以後都要再執行一次打包命令,這很是不方便,webpack能不能監聽到源代碼發生修改以後自動幫咱們再次打包?

強大的webpack給咱們提供了不少種方式,這裏簡要介紹兩種:

(1)直接在package.json文件中的scripts中配置,執行npm run watch便可:

"scripts": {
    "watch": "webpack --watch"
  },
複製代碼

(2)藉助webpackDevServer

  • 安裝webpack-dev-server

    npm install webpack-dev-server -D
    複製代碼
  • 在webpack.config.js文件中配置devServer:

    devServer: {
        // 告訴服務器從哪一個目錄中提供內容
        contentBase: './dist',
        // 打包結束後自動啓動瀏覽器進入localhost:8080下的頁面
        open: true
      }
    複製代碼
  • 在package.json文件中的scripts中配置,執行npm run start啓動服務:

    "scripts": {
        "bundle": "webpack",
        "watch": "webpack --watch",
        "start": "webpack-dev-server"
      }
    複製代碼

    注意:在webpackDevServer時還能夠配置代理轉發,好比:

    module.exports = {
      //...
      devServer: {
        proxy: {
          '/api': 'http://localhost:3000'
        }
      }
    };
    複製代碼

    以上代理的意思是當請求到/api/xxx時會代理到請求http://localhost:3000/api/xxx,這樣子使咱們前端在數據mock時不須要使用Charles等代理工具。

    番外篇:結合express和webpack-dev-middleware集成webpack小型server

    在網上偶然看到webpack藉助webpack-dev-middleware和express也能夠集成相似webpackDevServer的小型Server,具體步驟以下:

    (1) 安裝服務所需的包和依賴:

    npm install express webpack-dev-middleware -D
    複製代碼

    (2)在webpack.config.js文件中配置生成新文件所指向的路徑即publicPath:

    // 配置webpack打包的輸出文件
      output: {
        publicPath: '/',
        // 配置打包完成後的文件名
        filename: '[name].js',
        // 配置打包完成後的文件存放目錄(絕對路徑)
        path: path.resolve(__dirname, 'dist')
      }
    複製代碼

    (3)在package.json文件中的scripts中配置:

    "scripts": {
        "bundle": "webpack",
        "watch": "webpack --watch",
        "start": "webpack-dev-server",
        "server": "node server.js"
      }
    複製代碼

    (4)在項目跟webpack.config.js同級目錄下建立server.js,編寫代碼以下:

    const express = require("express");
    const webpack = require("webpack");
    const webpackDevMiddleWare = require("webpack-dev-middleware");
    // 引入webpack的配置文件
    const config = require("./webpack.config");
    
    // 導入配置文件建立webpack的編譯器
    const complier = webpack(config);
    
    // 建立基於express的node web服務器
    const app = express();
    
    // express服務集成webpack-dev-middleware中間件
    app.use(webpackDevMiddleWare(complier, {
      // 配置生成新文件所指向的路徑,須要使用相對路徑
      publicPath: config.output.publicPath
    }));
    
    // 啓動sever時監聽3000端口
    app.listen(3000, ()=> {
      console.log("server is running");
    })
    複製代碼

    (5)執行npm run server運行服務,並在瀏覽器輸入localhost:3000進入頁面

熱模塊更新HotModuleReplacementPlugin

在開發過程當中,特別是前端開發一些html和css樣式的調整,咱們並不想刷新整個瀏覽器的頁面,只是想webpack幫咱們覆蓋掉咱們修改的那部分html和css代碼,相似於局部刷新,熱模塊更新HotModuleReplacementPlugin可以很好地幫咱們解決這個問題,具體實現步驟以下:

(1)在webpack.config.js文件中配置處理導入css文件的打包處理方式:

{
      test: /\.css$/,
      use: [
        // 從下到上執行
        'style-loader',
        'css-loader',
        'postcss-loader'
      ]
    }
複製代碼

(2)webpack.config.js文件中配置熱更新:

// 熱更新plugin是在webpack底下,全部要先引入webpack
const webpack = require('webpack');

// 在devServer中啓用熱更新
 devServer: {
    // 告訴服務器從哪一個目錄中提供內容
    contentBase: './dist',
    // 打包結束後自動啓動瀏覽器進入localhost:8080下的頁面
    open: true,
    port: 8080,
    // 啓用熱模塊更新
    hot: true,
    // 在html出現問題時不讓webpack幫咱們自動刷新,而是直接給咱們報錯
	hotOnly: true
  }

// 在plugins下建立plugin實例
new webpack.HotModuleReplacementPlugin()
複製代碼

(3)在src目錄下新建style.css文件,代碼以下:

div:nth-of-type(odd) {
	background: blue;
}
複製代碼

(4)src下新建index.js,代碼以下:

import './style.css';
var btn = document.createElement('button');
btn.innerHTML = '新增';
document.body.appendChild(btn);

btn.onclick = function() {
	var div = document.createElement('div');
	div.innerHTML = 'item';
	document.body.appendChild(div);
}
複製代碼

(5)執行npm run start啓動服務,瀏覽器中點擊新增按鈕,發現奇數行的div爲藍色,咱們修改style.css的background顏色爲green

div:nth-of-type(odd) {
	background: green;
}
複製代碼

保存時回到瀏覽器發現建立的item個數還在,item的顏色也變成了綠色,實現css模塊熱更新。

注意:有時候咱們在js中要想實現js模塊熱更新,webpack也有對應的解決方式,以下例子:

(1)在src下新建counter .js、number.js和number1.js:

// counter .js
function counter() {
	var div = document.createElement('div');
	div.setAttribute('id', 'counter');
	div.innerHTML = 1;
	div.onclick = function() {
		div.innerHTML = parseInt(div.innerHTML, 10) + 1
	}
	document.body.appendChild(div);
}

export default counter;

// number.js
function number() {
	var div = document.createElement('div');
	div.setAttribute('id', 'number');
	div.innerHTML = 4000;
	document.body.appendChild(div);
}

export default number;

// number1.js
function number1() {
	var div = document.createElement('div');
	div.setAttribute('id', 'number1');
	div.innerHTML = 1000;
	document.body.appendChild(div);
}

export default number1;
複製代碼

(2)清除index.js的代碼添加以下代碼:

import counter from './counter';
import number from './number';
import number1 from './number1';

counter();
number();
number1();

if(module.hot) {
	module.hot.accept('./number', () => {
		// 先將id選擇器爲number移除
		document.body.removeChild(document.getElementById('number'));
		// 建立div並設置id爲number
		number();
	})

	module.hot.accept('./number1', () => {
		document.body.removeChild(document.getElementById('number1'));
		number1();
	})
}
複製代碼

(3)webpack.config.js中的熱更新已配置好,直接運行服務,瀏覽器打開先點擊幾下counter的計數器後修改number.js和number1.js中的div.innerHTML值,能夠發現頁面上number和number1的值都會變化可是counter值仍是保持在原先的計數值,並不會恢復成0。

在webpack下使用Babel處理ES6語法

如今ES6的一些語法已經逐漸代替了老版本的語法,可是一些瀏覽器還不能兼容ES6的一些新語法,使用Babel能夠將ES6語法轉換成ES5語法再讓瀏覽器執行。

在webpack中使用Babel處理ES6的步驟以下:

(1)首先在index.js中編寫須要轉譯的ES6代碼:

const arr = [
	new Promise(() => {}),
	new Promise(() => {})
];

arr.map(item => {
	console.log(item);
});
複製代碼

(2)安裝babel-loader、 @babel/core、@babel/preset-env、@babel/polyfill:

npm install babel-loader @babel/core @babel/preset-env @babel/polyfill -D
複製代碼

(3)配置webpack.config.js文件:

// 在module下配置
{
      test: /\.js$/,
      // 排除node_modules目錄下的js文件
      exclude: /node_modules/,
      loader: "babel-loader",
      options: {
        "presets": [["@babel/preset-env", {
          // 配置babel/polyfill根據業務代碼所用到的變量、函數才填充進去,這樣打包的文件就比較小
          useBuiltIns: 'usage'
        }]]
      }
    }
複製代碼

注意:這裏的babel-loader只是創建起webpack與babel轉譯器的橋樑,咱們還須要告訴webpack編譯的規則和環境,所以如上要配置presets

(4)若是此時直接執行npx webpack打包的話,發現打包後文件的末尾index.js代碼仍是有一些變量、函數沒有被轉譯,所以還須要在index.js導入@babel/polyfill彌補低版本瀏覽器一些變量、函數 :

// index.js
// @babel/polyfill能夠彌補低版本瀏覽器一些變量、函數
import "@babel/polyfill";
複製代碼
相關文章
相關標籤/搜索