超簡單的webpack,小白輕鬆學。

前言

說到學習webpack的艱辛歷程,那可真是一把鼻涕一把淚啊。我剛學習前端的時候,jquery的時代剛剛過去,入門前端就是學點js基礎,會寫一點css,而後直接用react和vue擼項目。你可能不知道爲何要這麼寫,但照着別人的代碼這麼寫是對的,就似懂非懂地開發項目了。css

至於webpack,那是什麼鬼,我直接用vue-cli3或者create-react-app就行了,只要項目跑得起來,誰管你要用webpack配置什麼東西。但理想是豐滿的,現實是骨感的,咱們不可能只用別人搭好的腳手架寫項目,要想實現不一樣應用場景下一些業務上的功能開發,還得本身動手配,真香。誰讓我走上了前端這條路呢,本身選的路,跪着也要繼續啊。html

這篇文章是我學習webpack的筆記,看心情更新,有生之年應該能更完。前端

爲何要打包代碼?

咱們編寫的css和js代碼運行在瀏覽器,能夠直接在控制檯的sources查看,若是不對代碼進行壓縮打包,代碼的邏輯就很容易被別人看到,這對咱們項目是很是不利的。vue

前端構建演變之路

原始時代

找在線的打包代碼網站上傳代碼,對代碼進行壓縮打包以後,再下載下來,放進咱們的項目裏面,可謂是異常艱辛。java

ant + YUI tool

YUI tool是07年左右出現的一個代碼打包工具,和java的ant配合使用,打包css和js代碼。由於當時的先後端還沒分離,是後端主導前端,因此前端的代碼都是嵌入到後端的項目裏去的。node

grunt

隨着業界requireJS模塊化的概念不斷催生,各類模塊化的代碼編寫也是愈來愈複雜,這時grunt誕生了,直到今天,grunt的社區生態依舊沒有衰減。他的本質就是運行在node上的命令行工具,它是一個任務運行器,將打包構建過程分紅一個一個的任務進行, 好比:解析HTML,解析CSS,解析JS,壓縮圖片,壓縮代碼等。每完成一個任務,就將這個任務的完成結果存放到本地磁盤的一個temp目錄中去,因此它的缺點也顯而易見,就是打包速度很慢,由於打包的時候進行了本地磁盤的IO操做。react

gulp

爲了解決grunt打包速度較慢的問題,gulp誕生了。gulp構建打包的本質和grunt同樣,也是分爲一個一個的任務去執行。但gulp有一個文件流的概念,它再也不把每一步構建的結果存放到磁盤中去,而是存放在內存中,這樣的話在構建的下一個步驟能夠直接在內存中讀取上一步構建的結果,大大加快了構建的速度。jquery

webpack及webpack基本概念

官方文檔介紹,本質上,webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。webpack

爲何如今使用webpack來打包項目的較多,有如下三個緣由。git

  • GitHub的stars數和周下載量遠高於grunt和gulp,社區生態豐富。
  • 配置靈活,可使用各類插件拓展,能夠本身定義loader和插件。
  • 官方插件數量豐富,能知足平常開發須要。
  • 官方更新迭代快,從14年至今,基本是一年發佈一個版本。

在webpack.config.js裏進行webpack的基本配置

module.exports = {
    entry:'./src/index.js',
    output:'./dist/main,js',
    module:{
        rules:[
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({template: './src/index.html'})
    ]
}
複製代碼

入口(entry):指示 webpack應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。webpack 會從入口找出有哪些模塊和庫是入口起點(直接和間接)依賴的。

出口(output):將打包成功的bundles文件輸出到出口目錄裏。

loader:webpack自身只能識別JavaScript,沒法識別非JavaScript文件。loader能夠將全部類型的文件轉換爲webpack可以識別的有效模塊。loader配置在module裏的rules裏,rules是一個數組,裏面能夠配置多個loader。

插件:loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務。插件配置到plugins這個數組裏,能夠配置多個插件。

第一個webpack程序

跟着個人命令,來實現咱們的第一個webpack程序

安裝webpack

首先,確保電腦安裝了nodeJS和npm,由於引入webpack須要依賴npm。
隨便進入一個文件夾,打開終端,執行如下命令:

mkdir webpack
cd webpack
npm init -y
複製代碼

npm init -y就是初始化咱們的項目,生成一個package.json文件,-y命令能夠省去敲回車確認的步驟,直接生成默認的package.json文件。以後執行下面的命令,將咱們的webpack依賴安裝進項目裏。

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

因爲webpack和webpack-cli是配套使用的,因此都須要安裝。--save-dev指的是將依賴安裝進devDependencies而不是Dependencies裏。devDenpendencies是開發環境,而Dependencies是生產環境。

安裝好的webpack會放在項目node_modules裏的bin目錄裏,能夠運行下面的命令來檢測webpack是否成功安裝。

./node_modules/.bin/webpack -v
複製代碼

一個最簡單的打包

在咱們剛纔新建的webpack文件夾裏建立一個叫webpack.config.js的配置文件,在webpack.config.js裏作以下配置:

const path = require('path');  // 引入path模塊

module.exports = {
    entry:'./src/index.js',   // 配置入口
    output:{                  // 配置出口
        path:path.join(__dirname,'dist'),  // path.join方法,用來拼接路徑,__dirname是當前路徑,這裏拼接起來就是當前路徑後面加上dist
        filename:'bundle.js'   // 打包的文件名
    },
    mode:'production'         //設置爲開發環境,不設置這個選項會報warning 
}
複製代碼

而後新建src目錄,在src目錄裏新建兩個文件,一個是index.js,也就是咱們的入口文件,另外一個是helloWebpack.js文件,在兩個文件分別寫如下代碼:

helloWebpack.js

export function helloWebpack(){
    return 'hello webpack';
}
複製代碼

index.js

import { helloWebpack } from './helloWebpack';
document.write(helloWebpack());
複製代碼

這裏咱們在helloWebpack.js裏寫了一個函數,返回一個字符串,在index.js裏引用這個函數,並打印在document上。

好了,代碼編寫完畢,你能夠點擊這裏查看項目如今的目錄結構

如今執行打包命令,因爲webpack是在node_modules下的bin目錄裏,因此得執行如下命令才能生效,以下圖所示:

./node_modules/.bin/webpack
複製代碼

若是你的顯示和我同樣,恭喜你,打包成功了。打包成功後,能夠看到咱們項目裏生成了一個dist目錄,dist目錄下有一個名爲bundle.js的文件,這就是咱們打包成功的文件。

不過點開這個bundle.js發現裏面的代碼都寫得很是奇怪還所有擠在一塊兒,這就是js代碼打包後的樣子,這樣咱們代碼的邏輯就不會暴露出來了。

咱們在dist裏新建一個index.html文件,在這個文件裏引入bundle.js,驗證bundles.js裏的代碼是否有效。

打開瀏覽器預覽index.html,發現成功輸出hello webpack。

說明咱們代碼打包成功,至此,咱們的第一個webpack程序就完成了。

經過npm scripts運行webpack

在上面的例子中,咱們打包的時候須要執行 ./node_modules/.bin/webpack命令,很麻煩,有沒有更簡單的辦法呢?實際上是有的,咱們能夠在package.json裏的scripts裏添加一個build命令來構建項目。
package.json

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.7"
  }
}
複製代碼

這是添加完命令後的package.json的樣子。接下來只須要在終端打開package.json所在的目錄,執行命令

npm run build
複製代碼

就能夠順利地將咱們的項目構建打包了,打包結果和上面的例子如出一轍(注意打包以前執行 rm -rf dist 命令將以前打包的結果刪除。)

什麼是npm腳本

像上例這樣寫在scripts裏的命令就是npm腳本。

"scripts": {
    "build": "webpack"
},
複製代碼

npm腳本scripts是一個對象,它的每個屬性,對應一個腳本。咱們能夠在scripts寫入多條腳本,好比咱們常見的vue-cli3中package.json中的scripts長這個樣子:

"scripts": { 
    "dev": "node build/dev-server.js",
    "start": "node build/dev-server.js",
    "build": "node build/build.js"
},
複製代碼

在這裏面,dev命令對應的腳本就是node build/dev-server.js,咱們執行npm run dev這個命令,等同於執行node build/dev-server.js。npm run start和npm run build同理。

npm腳本的原理及優勢

在上例中,執行npm run build,等同於執行 ./node_modules/.bin/webpack。 爲何會這麼神奇呢?

由於每當執行npm run,就會自動新建一個 Shell,在這個 Shell 裏面執行指定的腳本命令。所以,只要是 Shell(通常是 Bash)能夠運行的命令,就能夠寫在 npm 腳本里面。

比較特別的是,npm run新建的這個 Shell,會將當前目錄的node_modules/.bin子目錄加入PATH變量,執行結束後,再將PATH變量恢復原樣。

這意味着,當前目錄的node_modules/.bin子目錄裏面的全部腳本,均可以直接用腳本名調用,而沒必要加上路徑。好比,當前項目裏的依賴有webpack,直接寫webpack就能夠了。不信去查看node_modules下的.bin路徑,裏面確定有webpack這個js文件的。

使用npm腳本的優勢不少,好比:

  • 項目的相關腳本,能夠集中在一個地方。
  • 不一樣項目的腳本命令,只要功能相同,就能夠有一樣的對外接口。用戶不須要知道怎麼測試你的項目,只要運行npm run test便可。
  • 能夠利用 npm 提供的不少輔助功能。

第一階段小結

看到這裏,我想你對前端構建演變之路和webpack有了一個基本的瞭解。接下來咱們會更深刻地去學習webpack中入口,出口,loader和plugins的具體用法。

webpack核心概念

entry(入口)

entry就是webpack打包的入口,用來指示 webpack應該使用哪一個模塊,來做爲構建其內部依賴圖的開始。webpack 會從入口找出有哪些模塊和庫是入口起點(直接和間接)依賴的。

爲何咱們須要使用entry來找到全部須要打包的文件,這離不開webpack構建的方式。和其餘構建工具不一樣的是,webpack是一個模塊打包器。使用webpack打包,它會把一切的資源(js、css、圖片等文件)當成一個個的模塊。而這些模塊之間是存在依賴關係的,好比html頁面引入js、css,好比某個組件引入另外一個組件等等。所以,webpack會根據入口文件去找到入口文件的依賴,而這些依賴也會依賴別的文件,這樣就造成了如上圖所示的依賴關係圖。最後,將依賴關係圖裏的資源所有打包。

entry分爲兩種,單入口和多入口。單入口的entry是一個字符串,多入口的entry是一個對象。

單入口

module.exports = {
    entry:'./src/index.js'
}
複製代碼

多入口

module.exports = {
    entry:{
        index:'./src/index.js',
        user:'./src/user.js'
    }
}
複製代碼

顧名思義,單入口適用於一個項目裏只有一個入口文件,好比這個項目只有一個頁面或者是一個單頁應用。多入口適用用多頁應用的場景。

output(出口)

entry定義了輸入的資源,對應咱們的源代碼,output則定義了輸出的結果,對應轉換後的代碼。也就是說,咱們經過output來指定webpack編譯打包後的文件的輸出結果,具體到輸出的目錄和文件的名稱。
單入口

const path = require('path')

module.exports = {
    entry:'./src/index.js',
    output:{
        path:path.join(__dirname,'dist'),
        filename:'bundle.js'
    }
}
複製代碼

多入口

const path = require('path')

module.exports = {
    entry:{
        index:'./src/index.js',
        user:'./src/user.js'
    },
    output:{
        path:path.join(__dirname,'dist'),
        filename:'[name].js'
    }
}
複製代碼

單入口只須要配置輸出的路徑和文件名就能夠了,多入口同理,並非說有多個入口,就要配置多個出口,無論有多少個入口,都只有一個出口。

多入口的狀況下經過配置佔位符來確保文件名稱的惟一。filename裏的[name]就是一個佔位符,name就是文件打包出來的名稱,舉個具體的例子來看一下。

在剛纔的src文件裏新增一個user.js,在user.js裏隨意寫一些代碼 :

user.js

document.write(' userCenter page ');
複製代碼

接着配置webpack.config.js爲多入口的狀況:

webpack.config,js

const path = require('path');  

module.exports = {
    entry:{
        index:'./src/index.js',
        user:'./src/user.js'
    },   
    output:{                  
        path:path.join(__dirname,'dist'),  
        filename:'[name].js'   
    },
    mode:'production'
}
複製代碼

執行npm run build,最終打包生成了兩個文件。

去dist目錄下檢查,生成了index.js和user.js兩個文件。 點擊此連接查看文件目錄

loader

webpack只能識別js和json兩種文件類型,對於前端開發比較經常使用的css、less、vue、jsx等文件,是沒法識別的。loader能夠將這些類型的文件轉換爲webpack可以識別的有效模塊,這樣webpack才能把這些文件加入到打包的依賴圖中。

loader的本質是一個函數,接收源文件做爲參數,返回轉換的結果。

下圖展現了webpack中經常使用的loader

固然,官方的loader很是多,咱們須要用到的時候能夠去官網查怎麼使用,點擊這裏查看官方給出的loader

plugins的用法以下:

module.exports = {
    // ...
    module:{
        rules:[
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    }
}
複製代碼

loader配置在module裏的rules裏,rules是一個數組,裏面能夠配置多個loader。 在每個配置項裏,經過test去設置匹配規則,經過use來指定當前使用的loader的名稱。

plugins(插件)

loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。好比:

  • 管理文件資源
  • 優化打包輸出的bundles文件
  • 從新定義環境中的變量

通俗的講,plugins的做用就是加強webpack的功能,讓webpack能作更多的事,任何loader沒法作到的事,均可以經過plugins去完成。 plugins做用於整個構建過程。

下圖展現了經常使用的plugins:

固然,這只是一小部分plugins,更多插件能夠去官網查看,點擊這裏查看官方給出的plugins

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 經過 npm 安裝

module.exports = {
    // ...
    plugins:[
        new HtmlWebpackPlugin({template: './src/index.html'})
    ]
}
複製代碼

插件的用法很簡單,要使用什麼插件,就先用npm把這個插件安裝好,而後再把這個插件配置到plugins這個數組裏面去就行了。

mode(模式)

mode用來指定當前構建的環境,有development、production和none三種類型。

設置mode的好處是,能夠經過mode自動地觸發webpack內置的函數,好比設置mode爲development,那麼webpack會自動開啓在開發階段的一些實用的參數。好比,process.env.NODE_ENV的值就會變成development

mode的默認值爲production,若是不設置mode,webpack會自動開啓在生產階段的一些實用的參數和插件,若是將mode設置爲none,那麼webpack什麼也不會幫咱們作。

下圖展現了mode的內置函數功能:

mode的用法以下:

module.exports = {
    mode:'production'   // 'development','none'
}
複製代碼

。。。(待更新)

相關文章
相關標籤/搜索