webpack-易混淆部分的解釋

原文連接:javascript

https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9css

webpack的核心哲學

1. 任何皆模塊html

正如js文件能夠是"modules",任何其餘的文件,好比css, images, html均可以被視爲modules。也就是說,你能夠經過require("myJSfile.js")來加載js文件,也能夠經過require("mycssFile.css")加載css文件。這也就意味着咱們能夠將任何工做成果視爲更小的可管理的構建,可用於重用。java

2. 僅僅在你須要使用的時候,僅僅加載你須要的asset. 典型的,打包器接收全部的模塊輸入而最終生成以惡搞巨大的單個"bundle.js"文件.可是不少真實的應用,這個bundel.js文件可能會達到10MB-15MB的大小!所以,這種狀況下會致使加載很是慢。webpack爲了處理這種bundle過大的問題,webpack提供了幾個好用的功能用於split你的代碼,而且產生出多個"bundle" files,而且能夠async異步地加載parts of the app,以便僅僅加載你當前須要的部分。node

下面咱們來一個個探討容易搞不清楚的webpack topicreact

Development vs production

首先咱們要銘記在心的是webpack有很是朵的好功能,而這些功能中很大一部分僅僅是爲"development-only"的功能,而一部分是"production-only"的,而剩下的部分是既可用於開發環境,又可用於生產環境。webpack

典型地,大多數項目經過使用兩個大的webpack config file來分別處理dev和prod兩種場景。es6

要建立bundle,你可能會在package.json中這樣寫:web

"scripts":{
// npm run build to build production bundles
"build": "webpack --config webpack.config.prod.js",
// npm run dev to generate development bundles and run dev server
"dev": "webpack-dev-server"
}

webpack CLI vs webpack-dev-server

webpack,做爲打包工具,提供如下兩個接口,理解這一點很是重要:express

1. webpack cli tool---這是默認的接口(隨着webpack的安裝而存在於.bin目錄中)

2. webpack-dev-server tool ---一個node.js server(你須要單獨安裝它)

webpack CLI(很是適合作prodcution build)

這個命令行工具經過cli接收一些配置option,或者經過一個config file來接收這些option(默認爲webpack.config.js配置文件),這些配置選項將用於webpack的打包過程。

雖然你多是經過使用cli來開始學習webpack的,可是實際上命令行工具每每更多用於建立生產環境下使用的bundle.

用法:

OPTION 1: 
//Install it globally
npm install webpack --g
//Use it at the terminal 
$ webpack //<--Generates bundle using webpack.config.js

OPTION 2 :
//Install it locally & add it to package.json
npm install webpack --save
//Add it to package.json's script 
「scripts」: {
 「build」: 「webpack --config webpack.config.prod.js -p」,
 ...
 }
//Use it by running the following:
"npm run build"

webpack-dev-server(很是適合建立開發的build,並serve靜態的assets)

webpack-dev-server是一個運行於8080端口的expresss nodejs server.這個server會本身調用webpack自己實現構建,而且server構建出來的bundle.這個server的好處是它能夠提供好比"Live Reloading"或者"Hot Module Replacement(HMR)"的實用功能。

npm install webpack-dev-server --save
//Use it at the terminal
$ webpack-dev-server --inline --hot
OPTION 2:
// Add it to package.json's script 

「scripts」: {
 「start」: 「webpack-dev-server --inline --hot」,
 ...
 }
// Use it by running 
$ npm start
Open browser at:
http://localhost:8080

webpack vs webpack-dev-server options

須要說明的是,好比"inline"或者"hot"這些配置選項僅僅是對webpack-dev-server來適用的。而好比"hide-modules"僅僅針對webpack cli來講是適用的。

webpack-dev-server CLI options vs config options

另外須要說明的一點是:你能夠經過如下兩種方式來傳入webpack-dev-server配置選項options:

1. 經過webpack.config.js的"devServer對象

2.經過webpack-dev-server的CLI options傳入:

//Via CLI
webpack-dev-server --hot --inline
//Via webpack.config.js
devServer: {
 inline: true,
 hot:true
 }

我在測試中發現,有時經過devServer配置選項傳入參數(hot:true, inline:true)並不老是可以工做,因此,我更喜歡經過在package.json中的cli option來傳入對應的參數:

//package.json
{
scripts: 
   {「start」: 「webpack-dev-server --hot --inline」}
}

"hot" vs "inline" webpack-dev-server options:

 "inline"選項使得針對整個頁面實現"live reloading"成爲可能。"hot"選項使能了"hot module reloading"功能,而這個功能能夠僅僅reload那些被變動過的component(而不是整個頁面從新加載).若是咱們同時傳入兩個配置選項,那麼當source變化時,webpack-dev-server將會首先試圖作HRM,若是HMR不work,則會reload整個頁面。

//When the source changes, all 3 options generates new bundle but,
 
//1. doesn't reload the browser page
$ webpack-dev-server
//2. reloads the entire browser page
$ webpack-dev-server --inline
//3. reloads just the module(HMR), or the entire page if HMR fails
$ webpack-dev-server  --inline --hot

 

 "entry" --String Vs Array Vs Object

Entry這個配置項告訴webpack應用的root module或者starting point在哪裏。這個配置項能夠是string,能夠是array,也能夠是object.這個靈活性可能讓咱們搞得糊塗,可是這些不一樣類型的數據其實是用於不一樣的目的的。

若是你有一個single starting point的話,那麼string, array, object都是同樣的結果。

entry-array

可是,若是你想追加多個互不依賴的文件,那麼可使用array格式

好比,你可能須要"googleAnalytics.js"到你的html中,那麼你能夠告訴webpack追加該analytics.js到bundle.js的後面:

entry-object

若是你有一個多頁的web應用,有多個html文件(index.html, profile.html等),而不是一個SPA w/ multi-views, 

那麼你能夠經過entry object告訴webpack須要一次性建立多個bundles。

下面的配置將產生兩個js bundle文件:indexEntry.js和profileEntry.js分別應用於index.html和profile.html中

使用方法爲:

//profile.html
<script src=」dist/profileEntry.js」></script>
//index.html
<script src=」dist/indexEntry.js」></script>

entry-combination

你也能夠在object entry裏面使用array entries。例如,下面的config將產生3個文件:vendor.js和index.js, profile.js:

output-"path" vs "publicPath"

output告訴webpack咱們將最終的輸出存放在哪裏一級如何存放。這裏兩個參數:path和publicPath可能會產生歧義和誤解。

"path"告訴webpack咱們將最終的bundle存放在哪裏。耳"publicPath"則被多個webpack plugin來使用用於當產生production build時更新在html,css文件中的url

 

例如,在你的css中,你可能有一個url從你的localhost來load './test.png‘。可是在生產環境下,test.png文件可能存在於CDN中。這意味着你可能須要手工的更新這些url以便在生產環境中能夠指向到正確的url地址。

爲了解決這個手工修改url的問題,你可使用webpack的publicPath參數,而這個參數對幾乎全部的plugin都是可以理解並使用這個publicPath參數的,而且自動在建立production build時更新這些url.

 

 

// Development: Both Server and the image are on localhost
.image { 
  background-image: url(‘./test.png’);
 }
// Production: Server is on Heroku but the image is on a CDN
.image { 
  background-image: url(‘https://someCDN/test.png’);
 }

loaders and chaning loaders

loaders是一些額外的node modules專門用於幫助'load'或者'import'各類類型的文件到瀏覽器能夠認識的js, css文件格式。更進一步,loader也容許經過require或者import來import這些文件到js中。 

 例如:你可使用bable-loader來轉換es6寫的js代碼到瀏覽器能夠認識的es5 javascript:

module: {
 loaders: [{
  test: /\.js$/, ←Test for ".js" file, if it passes, use the loader
  exclude: /node_modules/, ←Exclude node_modules folder
  loader: ‘babel’ ←use babel (short for ‘babel-loader’)
 }]

 

 chaining loaders(從右往左)

多個loaders能夠級聯起來,針對同一個文件作不一樣的轉換。級聯是從右往左工做的,同時使用" ! "來隔離

例如,咱們若是有一個"mycssfile.css"文件,咱們須要將它的內容dump到html的<style>css content</style>中。咱們能夠經過如下兩個loaders來實現這個功能:css-loader和style-loader

module: {
 loaders: [{
  test: /\.css$/,
  loader: ‘style!css’ <--(short for style-loader!css-loader)
 }]

下面這張圖能夠解釋這個過程是如何工做的:

1. 首先webpack在module中檢索相關依賴,webpack看到mycssfile.css經過require來作import,所以mycssfile.css將做爲dependency來處理,webpack首先將該css文件給到'css-loader'來作處理

2. css-loader加載全部的css內容以及該css內容中本身的depency(好比@import othercss),並保存爲json. webpack而後將這個結果傳給style-loader繼續處理。

3. style-loader則接收這個json,而且增長<style>css contents</style>並將這個字符串插入到index.html文件中

loaders Themselves can be configured

loaders能夠經過傳入不一樣的parameters以不一樣的方式來工做。

在下面的例子中,咱們配置url-loader當image小於1024字節的話直接使用DataURLs。咱們能夠傳入limit參數來指定這個大小。

.babelrc文件

babel-laoder使用"presets"配置選項使能如何轉換es6爲es5的過程,一級如何解析react’s jsx 到js文件。咱們能夠經過query參數傳入配置:

module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015']
      }
    }
  ]
}

然而,不少項目中babel的配置項目可能不少,這種狀況下,你就能夠把balble的這些配置項目放到.babelrc文件中去。babel-loader將自動加載這個.babelrc文件若是它存在的話。

因此在不少例子中,你可能會看到:

//webpack.config.js 
module: {
  loaders: [
    {
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel'
    }
  ]
}

//.bablerc
{
 「presets」: [「react」, 「es2015」]
}

Plugins

plugins是一些針對輸出的bundle執行特別的工做的node modules.

例如,uglifyJSPlugin的做用是接收bundle.js做爲輸入而且混淆最小化該文件以減小文件的體積。

相似地,extract-text-webpack-plugin這個plugin則內部經過使用css-loader,style-loader來收集全部css內容並整合到一處並最終抽出這些css內容到一個單一的style.css文件中,而且在index.html中產生一個指向該style.css的link。

//webpack.config.js
//Take all the .css files, combine their contents and it extract them to a single "styles.css"
var ETP = require("extract-text-webpack-plugin");

module: {
 loaders: [
  {test: /\.css$/, loader:ETP.extract("style-loader","css-loader") }
  ]
},
plugins: [
    new ExtractTextPlugin("styles.css") //Extract to styles.css file
  ]
}

須要說明的是,若是你想在html中inline使用這些css樣式,你能夠不使用該plugin,而僅僅經過使用css, style loaders達到目的:

module: {
 loaders: [{
  test: /\.css$/,
  loader: ‘style!css’ <--(short for style-loader!css-loader)
 }]

loaders vs plugins

loaders僅在bundle生成過程當中或者生成以前針對單個的文件作轉換。

而plugin則在bundle建立的結束以後針對整個bundle或者chunk level執行操做。一些像commonsChunksPlugin的插件則更進一步會修正bundles自己是如何建立的過程。

resolving file extensions

不少webpack config文件有一個resolve extensions屬性,並有一個空字符串做爲值。

這個空字符串用於幫助resolve imports without extensions,好比require("./myJSFile")或者import myJSFile從"./myJSFile」而不用加上文件的擴展名.

{
 resolve: {
   extensions: [‘’, ‘.js’, ‘.jsx’]
 }
}
相關文章
相關標籤/搜索