Introduction to Webpack
Webpack is a module packaging tool. It creates modules for different dependencies and packages them all into manageable output files. This is especially useful for single page applications (the de facto standard for web applications today).
Suppose we have an application that can perform two simple mathematical tasks (addition and multiplication). For ease of maintenance, we decide to split these functions into different files.
index.html
<html> <head> <script src="src/sum.js"></script> <script src="src/multiply.js"></script> <script src="src/index.js"></script> </head> </html>
index.js
var totalMultiply = multiply(5, 3); var totalSum = sum(5, 3); console.log('Product of 5 and 3 = ' + totalMultiply); console.log('Sum of 5 and 3 = ' + totalSum);
multiply.js
var multiply = function (a, b) { var total = 0; for (var i = 0; i < b; i++) { total = sum(a, total); } return total; };
sum.js
var sum = function (a, b) { return a + b; };
The output of this application should be:
Product of 5 and 3 = 15 Sum of 5 and 3 = 8
How does Webpack help us?
We can't just use tools without knowing what these tools can help us do. So, what has Webpack done for us?
Use modules to rescue dependencies
In the above code, we can see that multiply.js and index.js all depend on sum.js. Therefore, if index.html imports dependencies in the wrong order, our application will not work. For example, if index.js is imported first, or sum.js is imported after multiply.js, you will get an error.
Based on the above example, let us imagine that a real web application may often contain up to dozens of dependencies. There may also be dependencies between these dependencies. Maintaining the relationships between these dependencies The sequence is breathtaking to think about. There may also be a risk of variables being overwritten by other dependencies, which will lead to hard-to-find bugs.
In order to solve this pain point, Webpack will convert dependencies into modules with smaller scopes to avoid variables being overwritten. An added benefit of converting dependencies into modules is that Webpack can manage these dependencies for us. The specific method is that Webpack will introduce dependent modules when needed and match the corresponding scope.
Reduce the number of HTTP requests through packaging
Let’s look back at index.html, in this file we Three separate files need to be downloaded. Of course, the files here are relatively small and can be dealt with, but the problem mentioned before is still there. In a real web application, there may be many dependencies, and this will cause the user to have to wait for all dependencies to be downloaded one by one before the main application can run. .
And this leads to another feature of Webpack - packaging. Webpack can package all dependencies into one file, which means that users only need to download one dependency and the main application can run.
To sum up, the main features of Webpack are Packaging and Modularization. By using plugins and loaders, we can extend these two features of Webpack.
Make the dependencies available and combine them
We will use CommonJS module syntax as an initial setup. Of course, there are other options such as AMD, ES2015, etc., but here we will use CommonJS first and migrate to ES2015 later.
CommonJS exports the module so that other code can use the functions or variables in the exported module. We can read the value in the exported module through require
.
index.html
<html> <head> <script src="./dist/bundle.js""></script> </head> </html>
index.js
var multiply = require('./multiply'); var sum = require('./sum'); var totalMultiply = multiply(5, 3); var totalSum = sum(5, 3); console.log('Product of 5 and 3 = ' + totalMultiply); console.log('Sum of 5 and 3 = ' + totalSum);
multiply.js
var sum = require('./sum'); var multiply = function (a, b) { var total = 0; for (var i = 0; i < b; i++) { total = sum(a, total); } return total; }; module.exports = multiply;
sum.js
var sum = function (a, b) { return a + b; }; module.exports = sum;
Observing the above code, it is not difficult to find that in order to allow function sum
and function multiply
to be To use, we exported these two functions in the sum.js and multiply.js scripts. There is a detail here. I don’t know if you have noticed it. In index.html, we only need to import one bundle.js file now.
This is a big help! We now no longer need to worry about the order of dependencies and can expose what we want to expose while keeping the rest private. Also, we now only need to import one file instead of three, which helps the app load faster.
Initial configuration of Webpack
In order to achieve the effect we want to achieve above, we need to do some initial configuration of Webpack.
var path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, './dist/'), filename: 'bundle.js' } }
Here we have implemented the simplest configuration. We at least need to tell Webpack where the entry point of our application is and what the output result should be. Let's take a closer look at what each attribute represents.
entry
: 這個(gè)屬性表示應(yīng)用的入口。入口就意味著,這是我們加載程序和程序邏輯的起點(diǎn)。Webpack將從這個(gè)入口開(kāi)始,遍歷整棵依賴樹(shù)。根據(jù)遍歷結(jié)果建立一個(gè)依賴間關(guān)系圖,并創(chuàng)建需要的模塊。output.path
: 這個(gè)屬性表示存放打包結(jié)果的絕對(duì)路徑。這里為了方便使用,我們采用了Node.js自帶的函數(shù)path
,這個(gè)函數(shù)能夠根據(jù)我們程序所處的位置,動(dòng)態(tài)的創(chuàng)建絕對(duì)路徑。其中,__dirname
是Node.js的一個(gè)工具變量,它表示當(dāng)前文件的目錄名。output.filename
: 這個(gè)屬性表示打包結(jié)果的文件名。它的名字可以是任意的,只不過(guò)我們習(xí)慣叫它bundle.js
。
來(lái)看看bundle.js
閱讀生成的bundle.js
代碼,可以給我們帶來(lái)一些啟發(fā)。
// the webpack bootstrap (function (modules) { // The module cache var installedModules = {}; // The require function function __webpack_require__(moduleId) { // Check if module is in cache // Create a new module (and put it into the cache) // Execute the module function // Flag the module as loaded // Return the exports of the module } // expose the modules object (__webpack_modules__) // expose the module cache // Load entry module and return exports return __webpack_require__(0); }) /************************************************************************/ ([ // index.js - our application logic /* 0 */ function (module, exports, __webpack_require__) { var multiply = __webpack_require__(1); var sum = __webpack_require__(2); var totalMultiply = multiply(5, 3); var totalSum = sum(5, 3); console.log('Product of 5 and 3 = ' + totalMultiply); console.log('Sum of 5 and 3 = ' + totalSum); }, // multiply.js /* 1 */ function (module, exports, __webpack_require__) { var sum = __webpack_require__(2); var multiply = function (a, b) { var total = 0; for (var i = 0; i < b; i++) { total = sum(a, total); } return total; }; module.exports = multiply; }, // sum.js /* 2 */ function (module, exports) { var sum = function (a, b) { return a + b; }; module.exports = sum; } ]);
從上面的代碼可以看出,Webpack把每一個(gè)js腳本都封裝到一個(gè)模塊中,并把這些模塊放進(jìn)數(shù)組中。模塊數(shù)組被傳入Webpack的引導(dǎo)程序中,引導(dǎo)程序會(huì)把這些模塊加入Webpack并執(zhí)行,使得模塊可用。
這里bundle.js
返回的是__webpack_require__(0)
,而這剛好對(duì)應(yīng)了模塊數(shù)組中的index.js
部分?;诖宋覀兺瑯涌梢缘玫秸_的運(yùn)行結(jié)果,而不需要處理依賴管理,下載依賴的次數(shù)也僅需要一次。
Loader讓W(xué)ebpack更好用
Webpack僅能理解最基本的JavaScript ES5代碼,它自身僅支持創(chuàng)建模塊并打包JavaScript ES5。如果我們不僅僅局限于JavaScript ES5,例如我們想使用ES2015,這就需要告訴Webpack如何處理ES2015。這里我們的處理方式往往是,我們需要將其它語(yǔ)言(如TypeScript)或其它版本(如ES2015)預(yù)處理成JavaScript ES5,再讓W(xué)ebpack做打包。這里就需要使用Babel來(lái)做轉(zhuǎn)換,把ES2015轉(zhuǎn)換為ES5(當(dāng)然Babel能做的事情遠(yuǎn)不止如此)。
為了說(shuō)明這個(gè)過(guò)程,我們使用ES2015重寫(xiě)之前的功能。
index.js
import multiply from './multiply'; import sum from './sum'; const totalMultiply = multiply(5, 3); const totalSum = sum(5, 3); console.log(`Product of 5 and 3 = ${totalMultiply}`); console.log(`Sum of 5 and 3 = ${totalSum}`);
multiply.js
import sum from './sum'; const multiply = (a, b) => { let total = 0; for(let i=0;i<b;i++) { total = sum(a, total); } return total; }; export default multiply;
sum.js
const sum = (a, b) => a + b; export default sum;
這里我們使用了很多ES2015的新特性,例如箭頭函數(shù)、const
關(guān)鍵字、模板字符串和ES2015的導(dǎo)入導(dǎo)出。ES2015的代碼Webpack無(wú)法處理,所以我們需要Babel來(lái)進(jìn)行轉(zhuǎn)換。想要讓Babel配合Webpack完成工作,我們就需要用到Babel Loader。事實(shí)上,Loader就是Webpack處理JavaScript ES5以外內(nèi)容的方式。有了加載器,我們就可以讓W(xué)ebpack處理各式各樣的文件。
想要在Webpack中使用Babel Loader,我們還需要三個(gè)Babel依賴:
babel-loader
: 提供Babel與Webpack之間的接口;babel-core
: 提供讀取和解析代碼的功能,并生成對(duì)應(yīng)的輸出;babel-preset-es2015
: 提供將ES2015轉(zhuǎn)換為ES5的Babel規(guī)則;
在Webpack中配置Babel Loader的代碼,差不多是下面這樣子:
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, './dist/'), filename: 'bundle.js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015'] } } ] } };
這段代碼你可以在webpack.config.js
中找到。值得注意的是,Webpack中是支持同時(shí)存在多個(gè)Loader的,所以提供的值是一個(gè)數(shù)組。接著,還是讓我們來(lái)看看每個(gè)屬性代表的含義。
test
: 我們只希望Loader處理JavaScript文件,這里通過(guò)一個(gè)正則表達(dá)式匹配.js文件;loader
: 要使用的Loader,這里使用了babel-loader
;exclude
: 哪些文件不需要被處理,這里我們不希望Babel處理node_modules下的任何文件;query.presets
: 我們需要使用哪個(gè)規(guī)則,這里我們使用Babel轉(zhuǎn)換ES2015的規(guī)則;
配置好這些內(nèi)容后,再次查看打包生成的bundle.js
,其中的內(nèi)容看起來(lái)就像下面這樣:
/* 2 */ function(module, exports) { var sum = function sum(a, b) { return a + b; }; module.exports = sum; }
可以看到,Babel Loader已經(jīng)把ES2015的代碼變成了ES5的代碼。
CSS與樣式,讓W(xué)ebpack看起來(lái)更出色
接下來(lái),讓我們拓展上面的例子,輸出計(jì)算結(jié)果。我們將在頁(yè)面上創(chuàng)建一個(gè)body
,然后把乘積與加和的結(jié)果添加到span
中。
import multiply from './multiply'; import sum from './sum'; const totalMultiply = multiply(5, 3); const totalSum = sum(5, 3); // create the body const body = document.createElement("body"); document.documentElement.appendChild(body); // calculate the product and add it to a span const multiplyResultsSpan = document.createElement('span'); multiplyResultsSpan.appendChild(document.createTextNode(`Product of 5 and 3 = ${totalMultiply}`)); // calculate the sum and add it to a span const sumResultSpan = document.createElement('span'); sumResultSpan.appendChild(document.createTextNode(`Sum of 5 and 3 = ${totalSum}`)); // add the results to the page document.body.appendChild(multiplyResultsSpan); document.body.appendChild(sumResultSpan);
這段代碼的輸出結(jié)果,應(yīng)該與之前是一致的,區(qū)別僅在于顯示在頁(yè)面上。
Product of 5 and 3 = 15 Sum of 5 and 3 = 8
我們可以使用CSS來(lái)美化這個(gè)結(jié)果,比如,我們可以讓每個(gè)結(jié)果都獨(dú)占一行,并且給每個(gè)結(jié)果都加上邊框。為了實(shí)現(xiàn)這一點(diǎn),我們可以使用如下的CSS代碼。
span { border: 5px solid brown; display: block; }
我們需要將這個(gè)CSS也導(dǎo)入應(yīng)用中。這里最簡(jiǎn)單的解決方案是,在我們的html中添加一個(gè)link
標(biāo)簽。但有了Webpack提供的強(qiáng)大功能,我們可以先導(dǎo)入它,再用Webpack來(lái)處理這個(gè)樣式。
在代碼中導(dǎo)入CSS帶來(lái)的另一個(gè)好處是,開(kāi)發(fā)者可以清晰的看到CSS與其使用之間的關(guān)聯(lián)。這里需要注意的是,CSS的作用域并不局限于它所導(dǎo)入的模塊本身,其作用域仍然是全局的,但從開(kāi)發(fā)者的角度看,這樣使用更加清晰。
import multiply from './multiply'; import sum from './sum'; // import the CSS we want to use here import './math_output.css'; const totalMultiply = multiply(5, 3); const totalSum = sum(5, 3); // create the body const body = document.createElement("body"); document.documentElement.appendChild(body); // calculate the product and add it to a span const multiplyResultsSpan = document.createElement('span'); multiplyResultsSpan.appendChild(document.createTextNode(`Product of 5 and 3 = ${totalMultiply}`)); // calculate the sum and add it to a span const sumResultSpan = document.createElement('span'); sumResultSpan.appendChild(document.createTextNode(`Sum of 5 and 3 = ${totalSum}`)); // add the results to the page document.body.appendChild(multiplyResultsSpan); document.body.appendChild(sumResultSpan);
這段代碼中,與前面代碼的唯一區(qū)別在于,我們導(dǎo)入了CSS。我們需要兩個(gè)Loader來(lái)處理我們的CSS:
css-loader
: 用于處理CSS導(dǎo)入,具體來(lái)說(shuō),獲取導(dǎo)入的CSS并加載CSS文件內(nèi)容;style-loader
: 獲取CSS數(shù)據(jù),并添加它們到HTML文檔中;
現(xiàn)在我們?cè)?code>webpack.config.js中的Webpack配置看起來(lái)像這樣:
const path = require('path'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, './dist/'), filename: 'bundle.js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015'] } }, { test: /.css$/, loaders: ['style-loader', 'css-loader'] } ] } };
我們還是來(lái)看看新增的CSS配置屬性所表示的內(nèi)容。
test
: 我們需要告訴Loader,我們只需要它處理CSS文件。這里的正則表達(dá)式僅匹配CSS文件。loaders
: 這里與前面不同的是,我們使用了多個(gè)Loader。還有一個(gè)需要注意的細(xì)節(jié)是,Webpack從右向左處理loader,因此css-loader
處理的結(jié)果(讀出CSS文件內(nèi)容)會(huì)被傳遞給style-loader
,最終得到的是style-loader
的處理結(jié)果(將樣式添加到HTML文檔中)。
假如我們現(xiàn)在需要提取CSS,并輸出到一個(gè)文件中,再導(dǎo)入該文件。為了實(shí)現(xiàn)這一點(diǎn),我們就要用到Plugin。Loader的作用在于,在數(shù)據(jù)被打包輸出前進(jìn)行預(yù)處理。而Plugin則可以阻止預(yù)處理的內(nèi)容直接出現(xiàn)在我們的打包結(jié)果中。
我們的Webpack配置現(xiàn)在變成了這樣:
const path = require('path'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, './dist/'), filename: 'bundle.js' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015'] } }, { test: /.css$/, loader: ExtractTextPlugin.extract('css-loader') } ] }, plugins: [ new ExtractTextPlugin('style.css') ] };
在這段代碼的頂部,我們導(dǎo)入了ExtractTextPlugin
,并使用這個(gè)插件改造了之前的CSS Loader。這里的作用是,css-loader
的處理結(jié)果不再直接返回給Webpack,而是傳遞給ExtractTextPlugin
。在底部我們配置了這個(gè)Plugin。
這里配置的作用是,對(duì)于傳遞給ExtractTextPlugin
的CSS樣式數(shù)據(jù),將會(huì)被保存在名為style.css
的文件中。這樣做的好處與之前處理JavaScript時(shí)一樣,我們可以將多個(gè)獨(dú)立的CSS文件合并為一個(gè)文件,從而減少加載樣式時(shí)的下載次數(shù)。
最終我們可以直接使用我們合并好的CSS,實(shí)現(xiàn)和之前一致的效果。
<html> <head> <link rel="stylesheet" href="dist/style.css"/> <script src="./dist/bundle.js""></script> </head> </html>
使用Webpack處理圖片
現(xiàn)在我們開(kāi)始嘗試向應(yīng)用中添加圖片,并讓W(xué)ebpack來(lái)協(xié)助我們處理這些圖片。這里我們添加了兩張圖片,一個(gè)用于求和,一個(gè)用于求積。為了讓W(xué)ebpack有能力處理這些圖片,我們使用這兩個(gè)Loader:
image-webpack-loader
: 嘗試幫助我們自動(dòng)壓縮圖片體積;url-loader
: 如果image-webpack-loader
的輸出圖片體積小,就內(nèi)聯(lián)使用這些圖片,如果image-webpack-loader
的輸出圖片體積大,就將圖像包含在輸出目錄中;
我們準(zhǔn)備了兩張圖片,用于求積的圖片(multiply.png)相對(duì)較大,用于求和的圖片(sum.png)相對(duì)較小。首先,我們添加一個(gè)圖片工具方法,這個(gè)方法會(huì)為我們創(chuàng)建圖片,并將圖片添加到文檔中。
image_util.js
const addImageToPage = (imageSrc) => { const image = document.createElement('img'); image.src = imageSrc; image.style.height = '100px'; image.style.width = '100px'; document.body.appendChild(image); }; export default addImageToPage;
接著,讓我們導(dǎo)入這個(gè)圖片工具方法,以及我們想要添加到index.js中的圖片。
import multiply from './multiply'; import sum from './sum'; // import our image utility import addImageToPage from './image_util'; // import the images we want to use import multiplyImg from '../images/multiply.png'; import sumImg from '../images/sum.png'; // import the CSS we want to use here import './math_output.css'; const totalMultiply = multiply(5, 3); const totalSum = sum(5, 3); // create the body const body = document.createElement("body"); document.documentElement.appendChild(body); // calculate the product and add it to a span const multiplyResultsSpan = document.createElement('span'); multiplyResultsSpan.appendChild(document.createTextNode(`Product of 5 and 3 = ${totalMultiply}`)); // calculate the sum and add it to a span const sumResultSpan = document.createElement('span'); sumResultSpan.appendChild(document.createTextNode(`Sum of 5 and 3 = ${totalSum}`)); // add the results to the page addImageToPage(multiplyImg); document.body.appendChild(multiplyResultsSpan); addImageToPage(sumImg); document.body.appendChild(sumResultSpan);
最后,我們還是來(lái)修改webpack.config.js
,配置兩個(gè)新的Loader來(lái)處理這些圖片。
const path = require('path'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { entry: './src/index.js', output: { path: path.resolve(__dirname, './dist/'), filename: 'bundle.js', publicPath: 'dist/' }, module: { loaders: [ { test: /.js$/, loader: 'babel-loader', exclude: /node_modules/, query: { presets: ['es2015'] } }, { test: /.css$/, loader: ExtractTextPlugin.extract('css-loader') }, { test: /.png$/, loaders: [ 'url-loader?limit=5000', 'image-webpack-loader' ] } ] }, plugins: [ new ExtractTextPlugin('style.css') ] };
還是老規(guī)矩,我們來(lái)看看新增的參數(shù)都表示什么含義。
output.publicPath
: 讓url-loader
知道,保存到磁盤(pán)的文件需要添加指定的前綴。例如,我們需要保存一個(gè)output_file.png
,那么最終保存的路徑應(yīng)該是dist/output_file.png
;test
: 還是和之前一樣,通過(guò)正則表達(dá)式匹配圖像文件,非圖像文件不處理;loaders
: 這里還是要再?gòu)?qiáng)調(diào)一下,Webpack從右向左處理loader,因此image-webpack-loader
的處理結(jié)果將會(huì)被傳遞給url-loader
繼續(xù)處理。
現(xiàn)在我們執(zhí)行Webpack打包,會(huì)得到下面三個(gè)東西。
38ba485a2e2306d9ad96d479e36d2e7b.png bundle.js style.css
這里的38ba485a2e2306d9ad96d479e36d2e7b.png
實(shí)際上就是我們的大圖片multiply.png
,較小的圖片sum.png
會(huì)被內(nèi)聯(lián)到bundle.js
中,就像下面這樣。
module.exports = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAMAAAACDyzWAAAC6FBMVEUAuv8AgL...."
這其實(shí)相當(dāng)于
img.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAMAAAACDyzWAAAC6FBMVEUAuv8AgL..."
更多編程相關(guān)知識(shí),請(qǐng)?jiān)L問(wèn):編程視頻??!
The above is the detailed content of What is Webpack? Detailed explanation of how it works?. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Vue is an excellent JavaScript framework that can help us quickly build interactive and efficient web applications. Vue3 is the latest version of Vue, which introduces many new features and functionality. Webpack is currently one of the most popular JavaScript module packagers and build tools, which can help us manage various resources in our projects. This article will introduce how to use Webpack to package and build Vue3 applications. 1. Install Webpack

Differences: 1. The startup speed of the webpack server is slower than that of Vite; because Vite does not require packaging when starting, there is no need to analyze module dependencies and compile, so the startup speed is very fast. 2. Vite hot update is faster than webpack; in terms of HRM of Vite, when the content of a certain module changes, just let the browser re-request the module. 3. Vite uses esbuild to pre-build dependencies, while webpack is based on node. 4. The ecology of Vite is not as good as webpack, and the loaders and plug-ins are not rich enough.

With the continuous development of web development technology, front-end and back-end separation and modular development have become a widespread trend. PHP is a commonly used back-end language. When doing modular development, we need to use some tools to manage and package modules. Webpack is a very easy-to-use modular packaging tool. This article will introduce how to use PHP and webpack for modular development. 1. What is modular development? Modular development refers to decomposing a program into different independent modules. Each module has its own function.

Configuration method: 1. Use the import method to put the ES6 code into the packaged js code file; 2. Use the npm tool to install the babel-loader tool, the syntax is "npm install -D babel-loader @babel/core @babel/preset- env"; 3. Create the configuration file ".babelrc" of the babel tool and set the transcoding rules; 4. Configure the packaging rules in the webpack.config.js file.

As the complexity of modern web applications continues to increase, building excellent front-end engineering and plug-in systems has become increasingly important. With the popularity of Spring Boot and Webpack, they have become a perfect combination for building front-end projects and plug-in systems. SpringBoot is a Java framework that creates Java applications with minimal configuration requirements. It provides many useful features, such as automatic configuration, so that developers can build and deploy web applications faster and easier. W

In vue, webpack can package js, css, pictures, json and other files into appropriate formats for browser use; in webpack, js, css, pictures, json and other file types can be used as modules. Various module resources in webpack can be packaged and merged into one or more packages, and during the packaging process, the resources can be processed, such as compressing images, converting scss to css, converting ES6 syntax to ES5, etc., which can be recognized by HTML. file type.

Webpack is a module packaging tool. It creates modules for different dependencies and packages them all into manageable output files. This is especially useful for single-page applications (the de facto standard for web applications today).

How does Webpack implement packaging? The following article will give you an in-depth understanding of Webpack packaging principles. I hope it will be helpful to you!
