webpack啟蒙教學(xué)

自我介紹環(huán)節(jié)

webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的模塊打包器(module bundler) 霞捡。當(dāng) webpack 處理應(yīng)用程序時(shí)榜揖,它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph)郎楼,其中包含應(yīng)用程序需要的每個(gè)模塊死嗦,然后將所有這些模塊打包成少量的 bundle(通常只有一個(gè)务甥,由瀏覽器加載)牡辽。

webpack.png

如上是webpack官網(wǎng)上的簡(jiǎn)介喳篇。從中我們可以看出webpack是一個(gè)模塊打包器,它獲取帶依賴的模塊并產(chǎn)生出與這些模塊相對(duì)于的靜態(tài)資源态辛。然而麸澜,自從發(fā)布后,webpack逐漸發(fā)展成為所有前端代碼的管理工具因妙。

為什么使用Webpack

分塊轉(zhuǎn)換的想法
模塊要能夠在客戶端中去執(zhí)行,則必須將它們通過(guò)請(qǐng)求從server端下載到browser端票髓。通常一個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)模塊攀涵,只有需要的模塊會(huì)被轉(zhuǎn)換。當(dāng)所有資源都在一個(gè)模塊中時(shí)洽沟,不需要的模塊也會(huì)被轉(zhuǎn)換以故,這樣就顯得很浪費(fèi)資源和時(shí)間。將眾多的模塊切成許多片裆操,在初始化時(shí)的請(qǐng)求不會(huì)包括完整的代碼怒详,并且在初始化時(shí)不需要的模塊切片會(huì)在后續(xù)加載過(guò)程中按需加載。并且將模塊化的切片方式是可以由開(kāi)發(fā)人員自己定義的踪区。

常用的模塊系統(tǒng)解決方案:
一昆烁、<script>標(biāo)簽類(lèi)型
最原汁原味的腳本引入方案,缺點(diǎn)如下(請(qǐng)不要問(wèn)我為什么不介紹優(yōu)點(diǎn)):

  • 全局作用域下造成變量的沖突缎岗;
  • 文件加載順序很重要静尼;
  • 模塊與模塊之間的依賴要解決;
  • 在大型項(xiàng)目中難以維護(hù)和管理传泊;

二鼠渺、CommonJs
該規(guī)范的核心思想是允許模塊通過(guò)require方法來(lái)同步加載所要依賴的其他模塊,然后通過(guò)exportsmodule.exports來(lái)導(dǎo)出需要暴露的接口眷细。

require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;

優(yōu)點(diǎn):

  • 服務(wù)端模塊能夠重復(fù)利用拦盹;
  • 有優(yōu)秀的包管理工具npm;
  • 簡(jiǎn)單溪椎,上手容易普舆;

缺點(diǎn):

  • 同步的模塊加載方式不適合在瀏覽器環(huán)境中,同步意味著阻塞加載校读,瀏覽器資源是異步加載的奔害;
  • 不能非阻塞的并行加載多個(gè)模塊;

三地熄、AMD
由于瀏覽器端的模塊不能采用同步的方式加載华临,會(huì)影響后續(xù)模塊的加載執(zhí)行,因此AMD(Asynchronous Module Definition異步模塊定義)規(guī)范誕生了端考。

define("module", ["dep1", "dep2"], function(d1, d2) {
  return someExportedValue;
});
require(["module", "../file"], function(module, file) { /* ... */ });

require接口用來(lái)加載一系列模塊雅潭,define接口用來(lái)定義并暴露一個(gè)模塊揭厚。
優(yōu)點(diǎn):

  • 適合瀏覽器的異步加載機(jī)制;
  • 并行加載模塊扶供;

缺點(diǎn):

  • 提高了開(kāi)發(fā)成本筛圆,代碼的閱讀和書(shū)寫(xiě)比較困難,模塊定義方式的語(yǔ)義不順暢椿浓;

四太援、CMD
CMD(Common Module Definition)規(guī)范和AMD很相似,盡量保持簡(jiǎn)單扳碍,并與CommonJS和Node.js的 Modules 規(guī)范保持了很大的兼容性提岔。在CMD規(guī)范中,一個(gè)模塊就是一個(gè)文件笋敞。

define(function(require, exports, module) {
  var $ = require('jquery');
  var Spinning = require('./spinning');
  exports.doSomething = ...
  module.exports = ...
})

優(yōu)點(diǎn):

  • 依賴就近碱蒙,延遲執(zhí)行;
  • 可以很容易在 Node.js 中運(yùn)行夯巷;

缺點(diǎn):

  • 依賴 SPM 打包赛惩,模塊的加載邏輯偏重;

五趁餐、ES6
EcmaScript6標(biāo)準(zhǔn)增加了JavaScript語(yǔ)言層面的模塊體系定義喷兼。在 ES6 中,我們使用export關(guān)鍵字來(lái)導(dǎo)出模塊后雷,使用import關(guān)鍵字引用模塊褒搔。需要說(shuō)明的是,ES6的這套標(biāo)準(zhǔn)和目前的標(biāo)準(zhǔn)沒(méi)有直接關(guān)系喷面,目前也很少有JS引擎能直接支持星瘾。

import "jquery";
export function doStuff() {}
module "localModule" {}

優(yōu)點(diǎn):

  • 未來(lái)的ES規(guī)范;

缺點(diǎn):

  • 瀏覽器對(duì)ES6的支持還需要一段時(shí)間惧辈;
  • 能夠依賴的現(xiàn)有的模塊少琳状;

webpack的目標(biāo)如下:

  • 拆分依賴樹(shù)成塊并按需加載;
  • 讓初始化加載時(shí)間更少盒齿;
  • 每一個(gè)靜態(tài)資源應(yīng)該是一個(gè)模塊念逞;
  • 能夠集成第三方類(lèi)庫(kù);
  • 適用于大型項(xiàng)目边翁;
  • 能夠定制模塊打包的每一個(gè)部分翎承;

webpack較之其他類(lèi)似工具有什么不同?

  • 有同步和異步兩種不同的加載方式符匾;
  • 加載器(Loaders)可以將其他資源整合到JS文件中叨咖;
  • 支持 CommonJs AMD 規(guī)范有豐富的開(kāi)源插件庫(kù),可以根據(jù)自己的需求自定義webpack的配置

眾所周知作為一個(gè)SEO的小TIPS,瀏覽器加載的資源越少甸各,響應(yīng)的速度也就越快垛贤,所以有時(shí)候我們通常會(huì)盡可能的將資源合并到一個(gè)主文件app.js里面。但有時(shí)候也會(huì)適得其反:當(dāng)項(xiàng)目十分龐大的時(shí)候趣倾,不同的頁(yè)面不能做到按需加載聘惦,而是將所有的資源一并加載,耗費(fèi)時(shí)間長(zhǎng)儒恋,性能降低善绎。會(huì)導(dǎo)致依賴庫(kù)之間關(guān)系的混亂,特別是大型項(xiàng)目時(shí)诫尽,會(huì)變得難以維護(hù)和跟蹤禀酱。

雖然webpack也會(huì)將所有資源放在一個(gè)文件里面,但是webpack可以很好的解決以上缺點(diǎn)箱锐,因?yàn)樗且粋€(gè)十分聰明的模塊打包系統(tǒng)比勉,當(dāng)你正確配置后劳较,它會(huì)比你想象中的更強(qiáng)大驹止,更優(yōu)秀。

webpack工作流程.png

核心概念

入口(Entry)
webpack 創(chuàng)建應(yīng)用程序所有依賴關(guān)系圖的起點(diǎn)观蜗。入口告訴 webpack 從哪里開(kāi)始臊恋,并根據(jù)依賴關(guān)系圖確定需要打包的內(nèi)容∧鼓恚可以將應(yīng)用程序的入口認(rèn)為是根上下文(contextual root)app 第一個(gè)啟動(dòng)文件抖仅。參見(jiàn)如下示例:

// 單入口
module.exports = {
  entry: {
     main: './src/main.js'
  }
}

// 多入口
module.exports = {
  entry: {
     app: ["./home.js", "./events.js"]
  }
}

// 多入口,app(應(yīng)用主入口)砖第,vendors(公共庫(kù))
module.exports = {
  entry: {
     app: './src/main.js',
     vendors: './src/vendors.js'
  }
}

出口(Output)
將所有的資源(assets)歸攏在一起后撤卢,還需要告訴 webpack 在哪里打包應(yīng)用程序。webpack 的 output 屬性描述了如何處理歸攏在一起的代碼(bundled code)梧兼。

const path = require('path');
module.exports = {
  output: {
    // 打包輸出的目錄放吩,這里是絕對(duì)路徑,必選設(shè)置項(xiàng)
    path: path.resolve(__dirname, './dist'),
    // 資源基礎(chǔ)路徑
    publicPath: '/dist/',
    // 打包輸出的文件名羽杰,也可以設(shè)置為[name].js渡紫,動(dòng)態(tài)對(duì)應(yīng)入口的定義
    filename: 'my-first-bundle.js' 
  }
}

加載器(Loader)
webpack 會(huì)把所有引用到的資源(.css, .html, .scss, .jpg, etc.) 都作為模塊處理。然而 webpack 自身只理解 JavaScript考赛。webpack loader 在文件被添加到依賴圖中時(shí)惕澎,將其轉(zhuǎn)換為模塊。在 webpack 的配置中 loader 有兩個(gè)目標(biāo):

  • 識(shí)別出(identify)應(yīng)該被對(duì)應(yīng)的 loader 進(jìn)行轉(zhuǎn)換(transform)的那些文件颜骤;
  • 轉(zhuǎn)換這些文件(test 屬性)唧喉,從而使其最終添加到 bundle 中(use 屬性);

示例如下:

module.exports = {
  module: {
    rules: [
      {
        // 這是個(gè)正則表達(dá)式
        test: /\.jsx$/,
        // 指定loader
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        // 指定多個(gè)loader
        use: [
          'css-loader',
          'style-loader'
        ]
      }
    ]
  }
}

插件(Plugins)
loader僅在每個(gè)文件的基礎(chǔ)上執(zhí)行轉(zhuǎn)換,而插件(plugins) 更常用于在打包模塊的 生命周期執(zhí)行操作和自定義功能欣喧。webpack 的插件系統(tǒng)極其強(qiáng)大和可定制化腌零。想要使用一個(gè)插件,你只需要 require() 它唆阿,然后把它添加到 plugins 數(shù)組中益涧。多數(shù)插件可以通過(guò)選項(xiàng)(option)自定義。你也可以在一個(gè)配置文件中因?yàn)椴煌康亩啻问褂猛粋€(gè)插件驯鳖,這時(shí)需要通過(guò)使用 new 來(lái)創(chuàng)建它的一個(gè)實(shí)例闲询。

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

// 應(yīng)用插件
const path = require('path');
const config = { 
    main: './src/main.js',
    output: { 
        path: path.resolve(__dirname, 'dist'), 
        filename: 'my-first-bundle.js' 
    }, 
    module: { 
        rules: [ 
            { test: /\.txt$/, use: 'raw-loader' } 
        ] 
    }, 
    plugins: [ 
        // 壓縮JS
        new webpack.optimize.UglifyJsPlugin(), 
        // 生成HTML
        new HtmlWebpackPlugin({template: './src/index.html'}) ,
        // 分離入口文件vendor作為單獨(dú)的模塊
        new webpack.optimize.CommonsChunkPlugin({
           name: 'vendor',
           filename: 'vendor.js'
        })
    ]
};
module.exports = config;

完整配置文件DEMO

**webpack.config.js**

var path = require('path'),
webpack = require('webpack'),
ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  devtool: 'eval',
  entry: {
    main: './src/main.js'
  },
  resolve: {
    // 自動(dòng)解析確定的擴(kuò)展
    extensions: ['.js', '.jsx'],
    // 告訴 webpack 解析模塊時(shí)應(yīng)該搜索的目錄
    modules: [
      path.resolve(__dirname, 'src'),
      'node_modules'
    ],
    alias: {
      'src': path.resolve(__dirname, './src')
    }
  },
  output: {
    // 打包輸出的目錄,這里是絕對(duì)路徑浅辙,必選設(shè)置項(xiàng)
    path: path.resolve(__dirname, './dist'),
    // 資源基礎(chǔ)路徑
    publicPath: '/dist/',
    // 打包輸出的文件名
    filename: 'build.js'
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          cacheDirectory: true
        }
      },
      {
        test: /\.css$/,
        /*
        use: [
          'css-loader',
          'style-loader'
        ]
        */
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader?minimize'
        })
      },
      // 支持less
      {
        test: /\.less$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [
            { loader: "css-loader?minimize" },
            { loader: "less-loader" }
          ]
        })
      },
      {
        // 處理圖片文件
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 7186, // inline base64 if <= 7K
          name: 'static/images/[name].[ext]'
        }
      },
      {
        // 處理字體文件
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 7186, // inline base64 if <= 7K
          name: 'static/fonts/[name].[ext]'
        }
      }
    ]
  },
  plugins: [
    // https://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    }),
    new ExtractTextPlugin({ filename: 'static/css/app.css', allChunks: true })
  ]
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扭弧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子记舆,更是在濱河造成了極大的恐慌鸽捻,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泽腮,死亡現(xiàn)場(chǎng)離奇詭異御蒲,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)诊赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)厚满,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人碧磅,你說(shuō)我怎么就攤上這事碘箍。” “怎么了鲸郊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵丰榴,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我秆撮,道長(zhǎng)四濒,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任像吻,我火速辦了婚禮峻黍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拨匆。我一直安慰自己姆涩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布惭每。 她就那樣靜靜地躺著骨饿,像睡著了一般亏栈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宏赘,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天绒北,我揣著相機(jī)與錄音,去河邊找鬼察署。 笑死闷游,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贴汪。 我是一名探鬼主播脐往,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扳埂!你這毒婦竟也來(lái)了业簿?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤阳懂,失蹤者是張志新(化名)和其女友劉穎梅尤,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體岩调,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巷燥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了誊辉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矾湃。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亡脑,死狀恐怖堕澄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霉咨,我是刑警寧澤蛙紫,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站途戒,受9級(jí)特大地震影響坑傅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喷斋,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一唁毒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧星爪,春花似錦浆西、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春久信,著一層夾襖步出監(jiān)牢的瞬間窖杀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工裙士, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留入客,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓腿椎,卻偏偏與公主長(zhǎng)得像痊项,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子酥诽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載训枢。 webpack介紹和使用 一托修、webpack介紹 1、由來(lái) ...
    it筱竹閱讀 11,137評(píng)論 0 21
  • GitChat技術(shù)雜談 前言 本文較長(zhǎng)恒界,為了節(jié)省你的閱讀時(shí)間睦刃,在文前列寫(xiě)作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,697評(píng)論 7 110
  • 無(wú)意中看到zhangwnag大佬分享的webpack教程感覺(jué)受益匪淺十酣,特此分享以備自己日后查看涩拙,也希望更多的人看到...
    小小字符閱讀 8,171評(píng)論 7 35
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門(mén)教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,185評(píng)論 40 247
  • 書(shū),不知要從何時(shí)說(shuō)起耸采。對(duì)于書(shū)的情感個(gè)人的情感很淡兴泥,上學(xué)的那些年并不是能沉得住氣的人,都說(shuō)看書(shū)的人能耐得住寂寞虾宇,在現(xiàn)...
    Zachary鴹羽閱讀 170評(píng)論 0 0