原文連接:javascript
https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9css
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
首先咱們要銘記在心的是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,做爲打包工具,提供如下兩個接口,理解這一點很是重要:express
1. webpack cli tool---這是默認的接口(隨着webpack的安裝而存在於.bin目錄中)
2. webpack-dev-server tool ---一個node.js server(你須要單獨安裝它)
這個命令行工具經過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是一個運行於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
須要說明的是,好比"inline"或者"hot"這些配置選項僅僅是對webpack-dev-server來適用的。而好比"hide-modules"僅僅針對webpack cli來講是適用的。
另外須要說明的一點是:你能夠經過如下兩種方式來傳入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」} }
"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這個配置項告訴webpack應用的root module或者starting point在哪裏。這個配置項能夠是string,能夠是array,也能夠是object.這個靈活性可能讓咱們搞得糊塗,可是這些不一樣類型的數據其實是用於不一樣的目的的。
若是你有一個single starting point的話,那麼string, array, object都是同樣的結果。
可是,若是你想追加多個互不依賴的文件,那麼可使用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告訴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是一些額外的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’) }]
多個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能夠經過傳入不一樣的parameters以不一樣的方式來工做。
在下面的例子中,咱們配置url-loader當image小於1024字節的話直接使用DataURLs。咱們能夠傳入limit參數來指定這個大小。
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是一些針對輸出的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僅在bundle生成過程當中或者生成以前針對單個的文件作轉換。
而plugin則在bundle建立的結束以後針對整個bundle或者chunk level執行操做。一些像commonsChunksPlugin的插件則更進一步會修正bundles自己是如何建立的過程。
不少webpack config文件有一個resolve extensions屬性,並有一個空字符串做爲值。
這個空字符串用於幫助resolve imports without extensions,好比require("./myJSFile")或者import myJSFile從"./myJSFile」而不用加上文件的擴展名.
{
resolve: {
extensions: [‘’, ‘.js’, ‘.jsx’]
}
}