webpack4.0 的配置及簡單使用

webpack

學習 webpack 能極大的擴充前端開發視野,所以推薦前端開發工程師,使用 webpack 構建工具。

webpack 4.0 相對於之前的版本,有了更多的變化,開發速度更快,大型項目能節約 90% 的構建時間。

webpack 4.0 內置了更多的默認配置,變更了許多 API

webpack 的簡單介紹

在面向對象的編程思想出現以前,我們都是使用面向過程的方式做網頁開發的。要向頁面中添加一些內容,必須要挨個創建,挨個編寫內容,然後挨個添加,如果頁面中的內容一多,就要編寫很多雷同的代碼,很容易形成代碼冗餘。

這個時候就出現了面向對象的編程思想,可以把頁面中的內容按模塊分裝單獨的業務邏輯文件。

面向對象要求將每個模塊封裝成對應的類,想要使用這個模塊(如table)時,從這個類中實例化一個對象即可,大大提高了代碼的可維護性。

但是如果劃分的模塊很多很大,每個類要單獨寫在一個 JS 文件中,這樣一個頁面中引入的 JS 文件次數就會變多,頁面會產生代碼冗餘,並且會增加服務器的加載負荷。而且這樣加載時,無法準確的知道項目的層級關係,還是不好管理。報錯不好調試。

所以我們希望,如果要在某個入口 JS 文件中使用其他 JS 文件的代碼,不用將這麼多的 JS 文件都引入同一個 HTML,在 JS 入口文件中自己引入其他 JS 文件,也就是 JS 文件之間可以互相引入,在 HTML 頁面中只引入邏輯入口文件。

這樣做的好處:

  • 不需要在 HTML 中引入很多的 JS 文件,提高文件加載速度。
  • 文件和文件之間的依賴關係會變得很明確,降低出錯率,提高代碼的可維護性。

ES6 Module 的語法可以提供這些功能:

import Header from './Header'
import Sidebar from './Sidebar'
import Content from './Content'
/*
...
 */

但是瀏覽器並不識別這樣的語法,需要做特殊的設置。 除了可以將 <script> 標籤的 type 屬性 設置爲 module 外,還可以使用 webpack 來解析這樣的語法,解析成瀏覽器能識別的語法格式(webpack 不僅可以打包 JS 文件,還可以打包其他任意文件,在框架中的使用可以體現其功能的強大)。

webpack 到底是什麼?

核心定義:webpack is a module bundler

webpack 是一個模塊打包工具。

爲了能讓代碼具備更高的複用性、可讀性和維護性,我們可以將網頁中的內容劃分成不同的模塊,使用 ES6 module
語法編寫腳本,最後使用 webpack 打包工具解析 import 語法,打包 JS 腳本,生成一個可以被瀏覽器識別的 JS 腳本文件。

webpack 也可以識別 CommonJS 模塊引入規範、CMDADM 模塊規範。

因爲 webpack 是模塊打包工具,所以它可以識別任何模塊封裝代碼。

webpack 最開始只打包 JS 的模塊。但是隨着技術的發展,JS 可以打包任何形式的模塊文件,這樣的代碼常出現在框架中。

webpack 環境搭建

webpack 是基於 node.js 開發的模塊打包工具,它本質上是由 node 實現的,要使用 webpack,必須先安裝 Node.js 的環境。

然後在指定的項目文件目錄中安裝 webpack

一、npm init

會在項目的目錄文件中生成一個 package.json 的項目文件,這個文件描述了這個項目的初始信息。

文件初始內容:

{
  "name": "webpack-demo",
  "version": "1.0.0",
  "description": "",
  "private": true, // 這個工具僅供自己使用,不會被髮布出去
  "author": "Guan Er",
  "license": "ISC" // 是否開源
}

二、全局或局部安裝 webpack

npm i webpack webpack-cli -g

npm i webpack webpack-cli --save-dev

驗證 webpack 安裝成功: webpack -v

一般情況下不建議全局安裝 webpack,以避免版本號變更帶來的各種問題。

在項目中安裝 webpack 成功之後,會在項目的目錄文件下生成一個 node_modules 的文件夾,其中包含了 webpack 和其依賴包的 JS 文件。

如果是局部安裝,就不能使用 webpack 命令(因爲這代表全局查找 webpack),node 提供了 npx 命令運行 webpack

如:
npx webpack -v;

npx 命令幫助我們在當前項目的目錄中找 webpack

webpack 的簡單配置

沒有配置文件時也可以打包,只不過要指定打包的文件,還要在命令行寫一些其他的。沒有配置文件時,我們使用的是官方提供的默認配置文件。

一、基礎配置

在項目的根目錄中新建 webpack.config.js 做配置:

// 引入node提供的 path 對象,來配置打包好的文件的路徑
const path = require('path');

// webpack 配置文件
module.exports = {
  entry: './index.js', // 指定要打包的入口文件路徑(根據入口文件和配置文件的相對目錄自擬)
  output: { // 打包好的文件的配置
    filename: 'over.js', // 打包好的文件的名稱
    // __dirname 指 webpack.config.js 所在的目錄
    // mydist 文件夾的絕對路徑是和 webpack.config.js 同級父目錄
    // 如果 path 不設置,那麼打包之後的文件夾默認叫 dist,文件名默認叫 main.js
    path: path.resolve(__dirname, 'mydist') // 打包好的文件的路徑
  }
};

以上配置文件的意義是:當在命令行輸入 npx webpack 命令並執行時,會將 webpack.config.js 文件同級目錄的 index.js 打包,打包之後會在 項目的根目錄下生成一個 mydist 文件夾,該文件夾中包含了一個 over.js 文件,是打包之後的腳本文件,在 html 中引入的腳本是 mydist 中的 over.js

注:

  • 當使用 npx webpack 命令打包時,要求配置文件必須叫 webpack.config.js
  • 如果配置文件叫其他名稱(如 config.js),還想正常打包,可以使用命令 npx webpack --config config.js

一般情況下,我們的項目目錄如下:

project                      // 根目錄
  node_modules               // webpack 及其依賴包
  dist                       // 打包之後的目錄
    index.html               // 項目的結構入口
    main.js                  // 打包之後的 js 文件,要引入到 index.html 中
  src                        // 源代碼列表
    index.js
  package.json
  package-lock.json
  webpack.config.js

二、利用 npm script 簡化打包代碼

有時候命令行的命令代碼過多,執行時比較麻煩,我們可以在 package.json 中的 script 做命令配置。
在 package.json 中,找到 scripts 配置對象,可以做命令的配置

// package.json
{ 
  ...
  "scripts": {
    // 運行 npm run start 時,運行 package.json 中的 scripts 對象中的 start 命令,會執行 webpack命令,此處的 webpack 可以不加 npx 修飾,會默認尋找當前目錄下的 webpack 命令,如果當前目錄沒有,再尋找全局的 webpack
    "start": "webpack"
  },
  ...
}

webpack-cli:

  • 使我們在命令行中正確的運行 webpack 的命令。如果不安裝這個包,就無法在命令行中使用 npx webpack 這樣的命令。

三、打包過程中容易出現的問題

打包時會遇到一個警告,告訴我們沒有指定配置環境。

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

需要在配置文件中指定 mode

module.exports = {
  mode: 'production',
  ...
};

mode 沒有設置時,底層打包時的默認值是 productionmode 設置爲 production,打包之後的 js 文件是被壓縮的,如果不想打包成壓縮文件,可以將 mode 設置爲 development

Webpack 打包示例

一、使用 Loader 打包圖片

index.js 中引入圖片:

import avatar from './1.png

會直接報錯:

ERROR in ./src/1.png 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
 @ ./src/index.js 4:0-28

webpack 默認指打包 js 文件,無法打包 png,想要實現打包,需要我們做配置。

安裝一個打包圖片時需要的工具:

npm i file-loader -D

然後在 webpack.config.js 配置文件中做配置:

// 引入node提供的 path 對象,來配置打包好的文件的路徑
const path = require('path');

// webpack 配置文件
module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: { // 打包非 js 文件時的配置
    rules: [{
      // 打包圖片時,使用 file-loader 工具
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'file-loader'
      }
    }]
  }
};

配置好之後重新打包,就不會再報錯,並且在 dist 目錄下,自動生成了一個新的圖片。

avatar 變量就代表 dist 目錄下的圖片的文件名, 可以在 JS 代碼中直接使用。

Loader 其實是 webpack 打包其他類型文件的解決方案。webpack 官方有非常完整的 Loader 體系,爲各種類型文件的打包提供瞭解決方案。

1. file-loader

打包其他類型文件時的更多配置:

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'file-loader',
        // 打包時的其他配置項:
        options: {
          // 打包之後的圖片名稱: 原文件名.原後綴名
          name: '[name].[ext]', // placeholder 佔位符配置法
          outputPath: 'images/' // 設置文件打包之後的父級目錄
        }
      }
    }]
  }
};

在上面的示例中,我們把 [name][ext] 稱爲佔位符,佔位符代表預留好的一些代表特殊功能的詞組,類似於代碼中的關鍵詞。
webpack 官方提供的佔位符裏列表非常詳細

2. url-loader

先在項目中安裝 url-loader

npm i url-loader -D

安裝之後將 webpack.config.js 中的圖片 loader 改爲 url-loader,重新打包,會發現打包依舊可以成功,但是圖片並沒有被打包到 dist 文件夾下。

但是圖片依舊正常顯示。

原因是當使用 url-loader 進行打包時,webpack 會將圖片打包成一個 base64 的字符串,放在 main.js 中,最終返回給 import 的變量。

這樣打包的好處是不用再發送請求生成一個圖片,但是也有弊端,就是當圖片比較大時,生成的 base64 的字符串也會非常長。這種情況可以給當前的options
添加一個 limit,規定 url-loader 打包的圖片的最大字節數,超出這個字節數會使用 file-loader 打包。

options: {
  name: '[name].[ext]',
  outputPath: 'images/',
  limit: 1024 // 大於 1k 的圖片使用 file-loader 打包
}

二、使用 Loader 打包樣式文件

1. 打包 css 文件

在項目的 src 目錄下新建一個 index.css 文件,在其中寫入任意的 css 代碼。

然後在 index.js 中通過 import 引入 css

...
import './index.css'
...

Vue 的腳手架中,這樣的代碼就可以直接生效,因爲 Vue 腳手架底層已經對 css 的打包做了配置。我們在我們的項目中直接打包會出錯,要像上面的圖片打包一樣,對 css 的打包做配置。

打包 css 樣式文件需要使用到 style-loadercss-loader,所以要先安裝它們。

npm i style-loader css-loader -D

webpack.config.js 文件中做出配置:

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.(png|gif|jpe?g)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 1024 
        }
      }
    },{
      test: /\.css$/,
      // 打包 css 文件時,需要兩個 loader,use 要設置成數據,不能是對象
      use: ['style-loader', 'css-loader']
    }]
  }
};

最後使用 npm run start 打包文件(這裏要運行的是 package.json 中配置好的 webpack 打包命令)。

打包之後 css 樣式就能生效於 html

css-loader 會分析出若干個 css 文件之間的關係,然後根據 css 的模塊引入 @import 引入鏈,將若干個 css 文件合併成一段 css 代碼。

可以在 src 目錄下再新建一個 avatar.css 文件,然後在 index.css 中引入:

@import './avatar.css'
/* 
index.css 的其他樣式代碼列表
 */

style-loader 會將 css-loader 生成的 css 代碼掛載在頁面的 <head> 標籤中。

打包之後頁面的 <head> 標籤中就會有一對 <style> 標籤,其中有所有的打包成功的 css 代碼。

2. 打包 lessscss 文件

在項目的根目錄下新建一個 index.scss 文件(可以將剛剛新建的 index.cssavatar.css 刪除),然後寫入一些 scss 代碼:

body {
  img {
     border-radius: 50%;
  }
}

將其引入到 index.js 中:

...
import './index.scss'
...

同樣的,需要安裝對應的 loader(官方文檔提示,打包 scss 文件時,需要安裝 sass-loadernode-sass 兩個包),然後在 webpack.config.js 中做一些配置,然後纔可以對其進行打包。

npm i sass-loader node-sass -D

配置:

// 在 rules 中增加 scss 文件的打包配置
{
  test: /\.scss$/,
  use: [
    'style-loader',
    'css-loader',
    'sass-loader'
  ]
}

注:
loader 的執行有嚴格的順序,如果一種文件的打包需要使用到很多種 loader,那麼先執行後配置的 loader,再執行先配置的 loader

3. 使用 postcss-loader 爲樣式自動添加樣式前綴

安裝:

npm i postcss-loader -D

還需要安裝一個 autoprefixer 的插件:

npm i autoprefixer -D

然後在項目根目錄下新建一個 postcss.config.js,要做一些配置:

module.exports = {
  plugins: [
    require('autoprefixer') // postcss 要使用的一個插件
  ]
};

然後在 webpack.config.js 中配置:

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

4. css-loader 的其他配置項

加入在 index.scss 中又引入了一個 header.scss 文件。

這種情況在直接打包時,不會使用經過 postcss-loadersass-loader ,而直接被 css-loader 打包,如果希望 header.scss 也能按順序被 postcss-loadersass-loader 打包,那就在 css-loader 中設置 importLoaders 值,需要經過幾個 Loader,就設置幾。

{
  test: /\.scss$/,
  use: [
    'style-loader',
    // 如果一個 loader 要做一些除默認配置之外的配置
    // 那麼在 use 中的表現形式應該是個對象
    {
      loader: 'css-loader',
      // css-loader 的其他配置項
      options: {
        importLoaders: 2
      }
    },
    'sass-loader',
    'postcss-loader'
  ]
}

5. css 打包模塊化

將樣式直接引入 index.js 打包之後,樣式會全局生效,這很容易產生問題,不同模塊的樣式可能會互相影響、覆蓋。

webpack 提供一個 css-module 的功能,讓指定樣式只生效於指定結構。

src 目錄列表:

header.scss
content.scss
header.js
content.js
index.js

代碼:

// header.scss
.header {
  width: 100%;
  background: #024987;
  h2 {
    color: #f00
  }
}
// content.scss
.content {
  width: 100%;
  background: #eee;
  h2 {
    color: #1E9FFF;
  }
}
// header.js
import HeaderStyle from './header.scss'

export default function() {
  var dom = document.getElementById('root');
  var el = document.createElement('div');
  el.className = HeaderStyle.header;
  el.innerHTML = '<h2>I am header</h2>';
  dom.appendChild(el);
}
// content.js
import ContentStyle from './content.scss'

export default function() {
  var dom = document.getElementById('root');
  var el = document.createElement('div');
  el.className = ContentStyle.content;
  el.innerHTML = '<h2>I am content</h2>';
  dom.appendChild(el);
}
// index.js
import Header from './header'
import Content from './content'

Header();
Content();

爲了能讓這種樣式代碼按模塊生效的功能打包成功,需要在 webpack.config.js 中做出相對應的配置:

{
  test: /\.scss$/,
  use: [
    'style-loader',
    {
      loader: 'css-loader',
      options: {
        importLoaders: 2,
        modules: true // 開啓 css-module 功能
      }
    },
    'sass-loader',
    'postcss-loader'
  ]
}

6. 打包字體文件

src 文件夾下新建一個 font 文件夾並放入一些字體文件。

font
  iconfont.eot
  iconfont.svg
  iconfont.ttf
  iconfont.woff

src 下新建 index.scss 並做字體設置:

@font-face {
  font-family: layui-icon;
  src: url(./font/iconfont.eot?v=240);
  src: url(./font/iconfont.eot?v=240#iefix) format('embedded-opentype'), url(./font/iconfont.svg?v=240#iconfont) format('svg'), url(./font/iconfont.woff?v=240) format('woff'), url(./font/iconfont.ttf?v=240) format('truetype');
}

.icon {
  font-family: iconfont;
}

.icon-reply-fill:before{ content:"\e611" }
.icon-set-fill:before{ content:"\e614" }

然後在稍微修改一下 index.js 中的代碼:

import Header from './header'
import Content from './content'
import IndexStyle from './index.scss'

Header();
Content();

var newEl = document.createElement('div');
newEl.classList.add(IndexStyle['icon-reply-fill']);
newEl.classList.add(IndexStyle['icon']);

document.getElementById('root').appendChild(newEl);

如果想讓上面的代碼能正常打包並生效,需要在 webpack.config.js 中對字體文件的打包做出配置:

// 在 rules 中新添加一個對象
{
  test: /\.(eot|ttf|svg|woff)$/,
  use: {
    loader: 'file-loader', // 打包字體文件需要的 file-loader
    options: {
      outputPath: 'font/' // 打包之後的字體文件在 dist 目錄中的路徑
    }
  }
}

然後打包項目,再運行,字體文件就能正常生效。

三、plugins 工具的簡單使用

plugins 的設置能讓打包過程更便捷,它相當於一個自動化打包工具,有很多打包過程如果不做配置,還是需要我們手動去修改或者書寫代碼,plugins 的作用就是讓一些代碼可以自動化的生成或修改。讓 webpack 的使用變得更加便捷。

webpack 官方提供了非常完善的 plugins 體系,我們下面以 html-webpack-plugin 做示範。

一般情況下,我們在項目研發中,會有一個 HTML 源代碼入口文件,項目上線時,需要上線打包之後 dist 目錄中的代碼。那在打包時,我們也希望在 dist 目錄中自動生成一個 html 文件,其中保留源代碼結構入口中的所有內容,並且還將 dist 中的腳本直接引入到這個 html 文件中。

html-webpack-plugin 就可以實現這樣的功能。

可以將示例項目中的 dist 目錄先刪除,然後在 src 目錄中新建 index.html 文件,在其中寫一些初始結構代碼:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title></title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

安裝:

npm i html-webpack-plugin -D

配置:

// webpack.config.js

const path = require('path');
// 要是用插件,需要現在配置文件中引入
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  module: {...},
  plugins: [new HtmlWebpackPlugin({
    template: 'src/index.html' // 結構模板
  })]
};

然後打包,會在 dist 目錄中自動生成一個 index.html 文件,這個文件中有源代碼結構文件中的所有結構代碼,邏輯入口 main.js 也被直接引入其中了。

plugins 可以在 webpack 運行到某個時刻時,自動執行一些動作。

參考資料
webapck 官方文檔
Dell Lee 的 webpack4.0視頻課程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章