Webpack - 核心概念

如果你稍微了解過 HTTP,肯定知道一大堆文件請求對(duì)于瀏覽器是什么樣的災(zāi)難。然而,數(shù)以百計(jì)的 JS 文件和 CSS 文件在現(xiàn)在的 Web Applications 中已經(jīng)是常態(tài)了,這么多的文件如果一個(gè)個(gè)通過 HTML 標(biāo)簽引入,別說瀏覽器,自己都要瘋掉。

簡單來說,Webpack 就是一個(gè)打包工具,它可以讓你把眾多文件,合并成一個(gè)。就像 Webpack 官網(wǎng)圖里展示的那樣。

bundle everything

對(duì)一個(gè)沒有引入 Webpack 的項(xiàng)目來說,如果要實(shí)現(xiàn)這種效果,最先遇到的問題就是:

  • 要怎么打包?
  • 打包之后的文件會(huì)在哪?

解決了這兩個(gè)問題,我們就能在項(xiàng)目里開始使用 Webpack 了。

所有問題的答案,都可以在 Webpack 的配置文件 webpack.config.js 中找到。

基礎(chǔ)概念

對(duì)于第一個(gè)問題,要怎么打包?
這是 Webpack 要考慮的問題,但同時(shí)我們也需要考慮 -- 怎么讓 Webpack 知道把 哪些文件 打成一個(gè) bundle?

Entry

以 JS 文件為例,通常來說,項(xiàng)目中的 JS 文件之間都是相互依賴的。你極有可能需要把 util.js 通過 import 引入另一個(gè)業(yè)務(wù)相關(guān)的文件 work.js 。那么 work.js 在被打包的時(shí)候, 它依賴的 util.js 也需要被打包在同一個(gè) JS 文件中, 程序的邏輯才不會(huì)被破壞。
如果通過引用一直向上溯源的話,通常會(huì)找到命名類似 src/index.js 的文件,它直接或間接的引用了幾乎所有的 JS 文件(Webpack 可以將文件打包為多個(gè),這里我們只考慮打包為一個(gè)的情況,認(rèn)為 index.js 引用了所有文件)。那么我們?nèi)绻麖?index.js 出發(fā),將它所有直接或間接通過 import 引用的文件全部都打包進(jìn)一個(gè) JS 文件 ,那 index.js 就是我們打包的開始、起點(diǎn)、入口,Webpack 中稱為:entry。

module.exports = {
  entry: './src/index.js'
};

entry 可以接收字符串、對(duì)象和數(shù)組。

Webpack 認(rèn)為,如果一個(gè)文件依賴于另一個(gè)文件(非代碼資源,像是圖片,Web 字體等),就存在 dependency。Webpack 從 entry 開始處理,遞歸地建立一個(gè) dependency graph,包含工程所需的所有文件,最終將它們打包為一個(gè)文件供瀏覽器加載。

那這個(gè)文件最終會(huì)在哪,文件名又是什么呢?知道這些信息我們就可以在 index.html 中直接引用它。

Output

這個(gè)問題的答案當(dāng)然是自己定,我們可以通過 output 屬性指定將來打包完畢的文件所在的路徑,以及文件名。Webpack 4 中的默認(rèn)值為 ./dist/main.js ( dist : distribution ),配置方式:

const path = require('path');

module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
};

pathfilename 分別指定 bundle 文件所在文件夾的絕對(duì)路徑的和文件名。

似乎問題已經(jīng)解決了?是的,目前為止我們已經(jīng)可以打包 JS 了。
只不過還有一些問題,比如我們需要打包的 JS 文件中不能使用 ES6 的特性,不能在 JS 中引入 CSS 文件(包括 SASS 文件),打包后文件數(shù)量數(shù)量少了但 bundle 文件所占空間還是比較大。

前面兩個(gè)問題是打包途中就需要考慮的,如果 Webpack 不能處理引入的文件(CSS 文件 和 瀏覽器不能辨識(shí)的 ES6 JS 文件),那打包的過程勢必會(huì)收到影響。
最后一個(gè)問題在 bundle 文件生成后處理就可以,比如壓縮一下文件。

這兩類問題都需要額外的工具協(xié)助。

對(duì)于第一類問題,我需要可以解析引入到 JS 的 CSS 文件的工具(css-loaderstyle-loader),以及將 ES6 標(biāo)準(zhǔn)下的 JS 轉(zhuǎn)為瀏覽器能識(shí)別版本的工具( babel-loader )。 Webpack 將這些解析工具稱為 loader。

Loaders

Webpack 只理解 javascript 和 json,Loaders 可以讓 Webpack 將其他文件轉(zhuǎn)化為 module,隨后就可以加入 denpendency graph。

Loaders 有兩個(gè)屬性可以在 config 文件中配置:

  • test : 指定要轉(zhuǎn)化的文件
  • use :指定轉(zhuǎn)化文件使用的 loader

對(duì)于上面的問題:

module.exports = {
  module: {
    rules: [
      { 
        test: /\.js$/, 
        use: 'babel-loader' 
      },
      { 
        test: /\.css$/, 
        use: ['style-loader', 'css-loader'] 
      }
    ]
  }
};

翻譯一下:

  • 當(dāng) webpack 的編譯器遇到某個(gè)文件中 require/importjs 結(jié)尾的文件時(shí), 先使用 babel-loader 轉(zhuǎn)化再打包。
  • 當(dāng) webpack 的編譯器遇到某個(gè)文件中 require/importcss 結(jié)尾的文件時(shí), 先使用 css-loaderstyle-loader 轉(zhuǎn)化再打包。

對(duì)于第二類問題,對(duì)打包好的 bundle 文件的處理,比如優(yōu)化、壓縮等等。通常通過一些插件進(jìn)行操作。

Plugins

比如常用的壓縮,Webpack 內(nèi)置這個(gè)插件。
這里我們更進(jìn)一步,通過 Webpack 插件生成 HTML 文件,并且自動(dòng)引入 bundle 之后的文件。顯然,Webpack 需要知道生成的 HTML 文件是什么樣子的,也就是它需要一個(gè)樣板、模板( template ),我們假設(shè)程序的入口 HTML 文件是 src/index.html,通過插件 html-webpack-plugin 來進(jìn)行這個(gè)操作。

使用 plugin 需要先通過 require 引入,再加入到 plugins 數(shù)組中。

const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins

module.exports = {
  plugins: [
    new webpack.optimize.UglifyJsPlugin({minimize: true}),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

現(xiàn)在我們直接使用 dist/index.html 就好了, Webpack 已經(jīng)打包了 JS、CSS 文件并一并注入了這個(gè) HTML 文件。

Plugin 還可以執(zhí)行更廣泛的任務(wù),如打包的優(yōu)化,資源管理和環(huán)境變量注入。大多 plugin 都可以定制化。

匯總

一份包含上面所有概念的 webpack.config.js 看起來差不多是這樣:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); 
const webpack = require('webpack'); 

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    rules: [
      { 
        test: /\.js$/, 
        use: 'babel-loader' 
      },
      { 
        test: /\.css$/, 
        use: ['style-loader', 'css-loader'] 
      }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin({minimize: true}),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

打包入口 entry ,輸出路徑 output,解析文件的 loader ,打包文件處理的插件 plugin。

今天就到這里了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容