1. 程式人生 > >webpack 模組化機制

webpack 模組化機制

為什麼需要模組化?

隨著網站內容越來越複雜,瀏覽器和使用者的互動越來越細膩,網站再也不是簡單的內容呈現,更像是一個複雜的客戶端軟體,其中html/css/js程式碼越來越多,邏輯越來越複雜,越來越不便於管理,為了解決這個問題,才出現了模組化的概念,也就是說模組化更多的是工程方面的產出,為了應對更復雜的網站開發。

梳理下網站的發展過程,大家也就知道為什麼模組化是必然出現的了:
✦ 早期一個html檔案,通過style引入內聯css,通過script引入內聯js。
✦ 晚一點一個html,通過link引入外部css,通過script引入外部js。
✦ 再複雜一點,多個html,各自引入自己的css和js。
✦ 再複雜一點,多個html中有複用的css和js,怎麼辦呢?拆分檔案唄,將css和js拆分成小檔案,然後通過link和script分別引入或者手動合併之後引入。
✦ 再複雜一點,有很多js/css的小檔案,手動解決會有缺陷或者容易出錯,怎麼辦呢?引入自動化工具唄,自動合併,壓縮等。
✦ 再複雜一點,想要按需合併js/css小檔案,開發模式自動監聽改動,甚至可以將圖片等其他靜態資源當做模組。
✦ 再複雜一點,…

到現在為止,都有哪些優秀的模組化方案呢?

非模組

通過多個script標籤引入多個js檔案,也即通過檔案的方式來管理模組。

這種原始的方案有很多顯而易見的弊端:
✦ 汙染全域性作用域,多人協作簡直是災難。
✦ 手動維護script標籤的順序,多頁應用更慘。
✦ 大型專案資源難以管理,容易留下隱患。

CommonJs,同步require

該方案的核心思想就是允許模組通過require方案同步載入依賴的其他模組,通過exports或module.exports來暴露出需要的介面。

require(“../moduleA.js”);

exports.doStuff = function() {
console.log(‘hello world’);
};
這種原始的方案的優點:
✦ 複用性強。
✦ 有不少可以拿來即用的模組,生態不錯。
✦ 實現簡單,使用簡單。

這種原始的方案的弊端:
✦ 同步載入不適合瀏覽器,瀏覽器的請求都是非同步載入。
✦ 不能並行載入多個模組。

AMD,非同步require

該方案只有一個主要介面define(id?, dependencies?, factory),他要在宣告模組的時候指定所有的依賴dependencies,並傳入到factory中,對於依賴的模組非同步載入並執行。

// 定義
define(“mymodule”, [“dep1”, “dep2”], function(d1, d2) {
});

// 載入
require([“module”, “../file”], function(module, file) {
});
這種原始的方案的優點:
✦ 非同步載入適合瀏覽器。
✦ 可並行載入多個模組。

這種原始的方案的弊端:
✦ 模組定義方式不優雅,不符合標準模組化

ES6模組

該方案最大的特點就是靜態化,靜態化的優勢在於可以在編譯的時候確定模組的依賴關係以及輸入輸出的變數。上面提到的CommonJs和AMD都只能在執行時確定這些東西。

import “jquery”;
export function doStuff() {}
這種原始的方案的優點:
✦ 可靜態分析,提前編譯。
✦ 面向未來的標準。

這種原始的方案的弊端:
✦ 瀏覽器原生相容性差,所以一般都編譯成ES5。
✦ 目前可以拿來即用的模組少,生態差。

webpack模組化機制

webpack並不強制你使用某種模組化方案,而是通過相容所有模組化方案讓你無痛接入專案,當然這也是webpack牛逼的地方。
有了webpack,你可以隨意選擇你喜歡的模組化方案,至於怎麼處理模組之間的依賴關係及如何按需打包,放輕鬆,webpack會幫你處理好的。

webpack的模組化有什麼特點?

✦ 可以相容多模組風格,無痛遷移老專案。
✦ 一切皆模組,js/css/圖片/字型都是模組。
✦ 靜態解析,按需打包,動態載入。

require(“./style.css”);
require(“./style.less”);
require(“./template.jade”);
require(“./image.png”);
本來,模組化方案僅僅是針對JS。但實際專案中,我們希望coffeescript也能被當做模組,進一步,css/less/sass是不是也可以被當做模組,再進一步,html/image/template是不是也可以被當做模組。
想到這些就覺得腦洞大開,不可思議!但是webpack居然做到了!webpack提供的loaders可以對檔案做預處理,從而實現了一切皆模組。

那麼,webpack到底對模組程式碼做了什麼?

非模組化程式碼

一行alert(‘hello world’);程式碼,經過webpack打包後,會生成如下50行程式碼;

/**/ (function(modules) { // webpackBootstrap
/**/ // The module cache
/**/ var installedModules = {};

/**/ // The require function
/**/ function webpack_require(moduleId) {

/**/ // Check if module is in cache
/**/ if(installedModules[moduleId])
/**/ return installedModules[moduleId].exports;

/**/ // Create a new module (and put it into the cache)
/**/ var module = installedModules[moduleId] = {
/**/ exports: {},
/**/ id: moduleId,
/**/ loaded: false
/**/ };

/**/ // Execute the module function
/**/ modules[moduleId].call(module.exports, module, module.exports, webpack_require);

/**/ // Flag the module as loaded
/**/ module.loaded = true;

/**/ // Return the exports of the module
/**/ return module.exports;
/**/ }

/**/ // expose the modules object (webpack_modules)
/**/ webpack_require.m = modules;

/**/ // expose the module cache
/**/ webpack_require.c = installedModules;

/**/ // webpack_public_path
/**/ webpack_require.p = “”;

/**/ // Load entry module and return exports
/**/ return webpack_require(0);
/**/ })
/**************************************************************/
/**/ ([
/* 0 */
/*/ function(module, exports) {

alert('hello world');

/*/ }
/**/ ]);
上面編譯出來的程式碼主要包含兩個部分:Runtime,模組。上半部分就是Runtime,作用是保證模組順序載入和執行。下半部分是我們的JS程式碼,包裹了一個函式,也就是模組。
執行的時候模組是作為Runtime的引數被傳進去的。

(function(modules) {
// Runtime
})([
// 模組陣列
])
那麼,非模組化程式碼被編譯後會有什麼缺陷呢?
✦ 模組不再暴露在全域性作用域,模組的全域性變數也不再是全域性變數。
✦ 模組被引入的時候只是執行程式碼而無法將模組賦值。因為非模組化規範的程式碼沒有通過AMD的return或者CommonJs的exports匯出模組本身。

AMD模組

AMD的程式碼

define([], function() {
alert(‘hello world!’);
});
經過webpack打包,會生成如下核心程式碼:

function(module, exports, webpack_require) {
var WEBPACK_AMD_DEFINE_ARRAY, // AMD依賴列表
WEBPACK_AMD_DEFINE_RESULT; // AMD factory函式的返回值,即模組內容

__WEBPACK_AMD_DEFINE_ARRAY__ = [];

// 執行factory函式,獲取返回值作為模組內容
// 函式體使用.apply呼叫,函式體中this為exports
// 形參則分別對應依賴列表中的各個依賴模組
__WEBPACK_AMD_DEFINE_RESULT__ = function() {
    alert('hello world!');
}.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__);

// 如果模組內容不為空,則通過module.exports返回
// 如果為空,則不處理,在Runtime中宣告為{}
if (__WEBPACK_AMD_DEFINE_RESULT__ !== undefined) {
    module.exports = __WEBPACK_AMD_DEFINE_RESULT__;
}

}
CommonJs

CommonJs的程式碼

var me = {
sayHello:function(){
alert(‘hello world!’);
}
};
module.exports = me;
經過webpack打包,會生成如下核心程式碼:

function(module, exports) {
var me = {
sayHello: function() {
alert(‘hello world!’);
}
};

module.exports = me;

}
模組化是拆分,那傳輸怎麼辦?

博文開頭提到,模組化是工程化的需求,是為了更好的管理程式碼,最後上線的程式碼並不應該是這樣的,假設我們用兩個極端的方式去載入程式碼:
✦ N個模組N個請求。
✦ 所有模組打包成一個檔案,一個請求。
顯然,這兩種都不是最優方案,第一種請求數量過多,第二種請求檔案過大。

理論上,最優方案是:按需打包,即將該頁面需要的所有模組打包成一個檔案,保證請求最少,且請求的程式碼都是需要的。

在webpack之前的構建工具裡,都實現不了這個“最優方案”,因為它們不知道模組之前的依賴關係,自然就不能按需打包了。
而webpack出現之後,它的程式碼分片功能讓webpack擁有了按需打包的特性,從而鶴立雞群。當然,webpack還有很多其他優秀的特性。

相關推薦

webpack 模組機制

為什麼需要模組化? 隨著網站內容越來越複雜,瀏覽器和使用者的互動越來越細膩,網站再也不是簡單的內容呈現,更像是一個複雜的客戶端軟體,其中html/css/js程式碼越來越多,邏輯越來越複雜,越來越不便於管理,為了解決這個問題,才出現了模組化的概念,也就是說模組

webpack模組開發

/* * @Author: 瓊歌先生 * @Date: 2018-07-30 14:07:03 * @Last Modified by: lastName.瓊歌先生 * @Last Modified time: 2018-07-31 16:51:19 */

模組機制

模組化 前端專案日益龐大,涉及到的業務方面越來越多,現在比較流行的是元件化開發,剩下就是模組化、工程化了。最新的ES6頁支援了類class和模組module屬性;對於模組化一直以來都不是特別清楚

現代富文字編輯器Quill的模組機制

    DevUI是一支兼具設計視角和工程視角的團隊,服務於華為雲DevCloud平臺和華為內部數箇中後臺系統,服務於設計師和前端工程師。官方網站:devui.designNg元件庫:ng-devui(歡迎Star) 引言 本文基於DevUI的富文字編輯器開發實踐和Quill原始碼寫成。

node,npm,webpack,vue-cli模組程式設計安裝流程

首先什麼都不要管,先裝環境。 pip是萬能的!!! 安裝node:  pip3 install node 安裝npm:   pip3 install npm 安裝webpack:  npm install webpack 安裝vue-cli:  npm install vue-

前端模組開發規範的終結者Webpack詳解(純乾貨,不套路)

可謂集CommonJS、AMD、ES6等多種特性於一身,靈活、易用、高擴充套件性、效能優越。 核心配置 以下是webpack的幾個核心配置節: 節點 說明 entry 指定要打包的檔案

webpack之css模組

前言本文演示了如何開始css模組化;如何選擇性的開啟部分css檔案的模組化功能;如何讓模組化後寫入html的class更具有可讀性;涉及到的loader: css-loader、style-loader開啟css-loader的模組化配置當前專案目錄和package.json

webpack構建——css的模組

    今天配置css模組化,一直出錯,最後發現原因是配置的問題。首先,看下面:webpack.config.js  :{ test: /\.css$/, use: [ 'style-loader', { loader: 'css-loa

6 JS的模組 ES6模組webpack打包

轉自:https://blog.csdn.net/u014168594/article/details/77198729js的模組化程序現在前端技術日新月異,對於同一個問題痛點,各個時段有各自的解決方案,這就帶來了很大差異。今天我就打算梳理js模組化的歷史程序,講一講這些方案

ES6模組webpack配置

webpack安裝 安裝 node & npm(因為webpack是基於node開發的) 通過 npm / yarn 的方式來安裝 webpack 安裝方式: 全域性安裝 npm install -g webpack -g : global

使用Webpack ES6轉ES5 實現模組(import export)

1.安裝nodejs:開啟nodejs官網https://nodejs.org/en/,點選碩大的綠色Download按鈕,它會根據系統資訊選擇對應版本(.msi檔案)。   開啟命令提示符執行下列命令(開啟方式:window + r 輸入cmd回車)   node -v檢

如何在 webpack 中引入未模組的庫,如 Zepto

前言 最近我在研究多頁面 webpack 模組打包的完整解決方案時,發現用 import 匯入 Zepto 時,會報 Uncaught TypeError: Cannot read property 'createElement' of undefined 錯誤,

從前端模組的概念來理解Webpack

為什麼需要模組化? 隨著網站內容越來越複雜,瀏覽器和使用者的互動越來越細膩,網站再也不是簡單的內容呈現,更像是一個複雜的客戶端軟體,其中html/css/js程式碼越來越多,邏輯越來越複雜,越來越不便於管理,多人協作成本加深,為了解決這些問題,才出現了模組化的

Webpack:前端資源模組管理和打包工具

 一.介紹:    Webpack 是當下最熱門的前端資源模組化管理和打包工具。它可以將許多鬆散的模組按照依賴和規則打包成符合生  產環境部署的前端資源。還可以將按需載入的模組進行程式碼分隔,等到實際需要的時候再非同步載入。通過 loader 的轉  換,任何形式的資源都可以視作模組,比如 CommonJs

webpack引入非模組檔案

webpack引入非模組化js的方法: 比如我們要在webpack專案中引入 qrcodejs(生成二維碼的外掛),外掛詳細程式碼如下: 解決辦法: 先安裝 exports-loader 檔案解析外掛: npm install -D exports-loader

webpack+vue+vueRouter模組構建完整專案例項詳細步驟-入門篇

新建專案 開始(確認已經安裝node環境和npm包管理工具) 1、新建專案檔名為start_vuedemo 2、npm init -y 初始化專案,我的win7系統,工程在d盤的vue_test_project資料夾下的名為start_vuedemo的工程資料夾 如圖所示: 在該工程下自動生成一個pac

1. webpack+vue+vueRouter模組構建完整專案例項詳細步驟-入門篇

新建專案開始(確認已經安裝node環境和npm包管理工具)1、新建專案檔名為start_vuedemo2、npm init -y 初始化專案,我的win7系統,工程在d盤的vue_test_project資料夾下的名為start_vuedemo的工程資料夾如圖所示:在該工程下自動生成一個package.jso

07 . 前端工程化(ES6模組webpack打包css,less,scss,圖片,字型,配置Vue元件載入器和釋出專案)

#### 模組化規範 ##### 傳統開發模式主要問題 ```go /* 1. 命名衝突 2. 檔案依賴 */ ``` `通過模組化解決上述問題` ```go /* 模組化就是把單獨的一個功能封裝在一個模組(檔案)中,模組之間相互隔離, 但是可以通過特定的介面公開內部成員,也可以

npm和webpack初始

文件 bsp -- bpa webpack mod .json 有一個 根據 1.npm初始化 在項目文件夾下執行npm init,根據提示回車或者填寫信息。結果是生成packge.json文件。 2.webpack初始化 先執行npm install webpack -g

探尋 webpack 插件機制

require article gif analyze 圖片 spa cal 開發 assets webpack 可謂是讓人欣喜又讓人憂,功能強大但需要一定的學習成本。在探尋 webpack 插件機制前,首先需要了解一件有意思的事情,webpack 插件機制是整個 web