最初翻譯於2017年1月初,後來以爲翻譯的很差就刪掉了...如今恢復~ 說不定對別人有幫助javascript
簡而言之,webpack是一個JavaScript模塊打包工具。可是它能夠用來託管而且管理你全部的前端代碼(至少它被開發出來的目的或者說社區但願達到的目標是這樣的)css
傳統的構建工具執行任務的方式是: 你的css以及javascipt等是分離的。你必須分開的去管理他們,而且你要確保每一項在生產環境中都是合適的狀態。html
好比gulp能夠擔當預處理器和轉換器的角色,可是每個場景下,它都會有源輸入(目錄或者文件)和一個編譯打包後的目標輸出(目錄或者文件)。可是它僅僅是按照這個規則一個接着一個的執行卻沒有在宏觀上去考慮如何和整個應用更好的結合。這會給開發者帶來一些負擔:如何選擇以及怎樣篩選合適的任務處理器;在生產環境中去將這些分離的部件很好的齧合到一塊兒。前端
Webpck拋出一些問題: 若是在開發的過程當中某一個工具會自行幫咱們處理應用中模塊之間的依賴, 咱們只須要專一在咱們本身的業務代碼層面以及最終產出,構建只須要通過簡單的配置 那麼狀況會變得怎麼樣呢?java
webpack的處理方式: 若是webpack知道你想要什麼,他只會打包生產環境中實際用獲得的模塊。node
若是你在最近幾年活躍在各大web社區,我想你已經知道了解決問題的辦法了: 使用javascript來實現。 Webpack嘗試去使用javascript來處理模塊之間的依賴使構建過程更加簡單。 可是這個設想強大的地方不是僅僅的模塊管理,而是整個構建層面100%是由javascript來實現,伴隨node的特性,它能夠作的更多。Webpack讓你可以寫出更契合系統的有效的javascript代碼。python
換句話說:你沒必要爲webpack編寫代碼,單純的for your project。
可是webpack可以和你的項目完美共生(固然須要增長一些額外的配置,若是你的項目有新的構建需求)react
簡而言之, 若是你曾經被下面的問題困擾過:webpack
那麼webpack應該會幫助到你,上面提到的問題,它都能經過javascript來解決。最棒的是什麼? Webpack能夠純粹的在服務端運行,這意味着你可使用webpack來開發漸進加強(progressively-enhanced)的websites。es6
咱們使用的是Yarn(brew install yarn),沒有用npm,這不影響咱們的後面的demo,他們達到的目的是同樣的。咱們在執行下面的命令,將webpack添加到全局module和本地項目中。
yarn global add webpack@beta webpack-dev-server@beta
yarn add --dev webpack@beta webpack-dev-server@beta
咱們新建一個webpack配置文件,在咱們項目的根目錄下面
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: './app.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
Note: __dirname
指向當前項目的根目錄
Webpack經過閱讀你的代碼 能夠‘知道’項目中運行的內容(‘別擔憂,它簽了保密協議的’),webpack作了下面幾件事:
context
目錄啓動, …output.path
目錄下面,而且是以output.filename
命名的([name]將會被entry的key替換)。 src/app.js
以下,你須要提早安裝moment到項目中(yarn add moment
)
import moment from 'moment';
var rightNow = moment().format('MMMM Do YYYY, h:mm:ss a');
console.log(rightNow);
// "October 23rd 2016, 9:30:24 pm"
而後運行
webpack -p
Note: The p flag is 「production」 mode and uglifies/minifies output. 這個-p參數 全名字是 production,它會幫咱們壓縮輸出的文件。
你會看到在dist/app.bundle.js
裏面記錄了日期時間而且有console語句。注意到webpack自動將moment
引入了,由於app.js文件裏面require了這個包。(儘管若是你當前目錄有一個moment.js的文件,然而webpack會優先引用Node Module裏面的moment module)
You can specify any number of entry/output points you wish by modifying only the entry object.
你能夠修改entry對象來指定任意數量的入口/輸出文件,entry的值能夠是字符串,數組,對象。
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: ['./home.js', './events.js', './vendor.js'],
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
Will all be bundled together as one dist/app.bundle.js file, in array order. 最終會將這3個文件一塊兒打包進disa/app.bundle.js
文件,按照數組的索引來排序
const path = require('path');
const webpack = require('webpack');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
home: './home.js',
events: './events.js',
contact: './contact.js',
},
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].bundle.js',
},
};
固然你也能夠選擇將多個js文件打包進你的app,在dist目錄下會有三個文件 home.bundle.js
, events.bundle.js
,contact.bundle.js
若是你將你的應用分別打包,輸出多個文件(若是你的app內部存在巨量的js,而這個js你不須要提早加載這就有必要了),有可能在打包以後的多個文件可能有重複的代碼,由於webpack將多個文件內須要的依賴依次打包進了多個目標文件裏面。幸運的是 webpack提供了CommonsChunk插件來解決這個問題:
module.exports = {
// …
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'commons',
filename: 'commons.js',
minChunks: 2,
}),
],
// …
};
如今,在你的輸出目標文件內,若是有任何模塊被加載了2次(這個是由參數minChunks
來決定的),那麼這個模塊將會被打包進一個名字爲common.js(看上面代碼由參數filename
來決定)這個文件能夠緩存到客戶端,雖然多一次額外的網絡請求,可是這也阻止了客戶端屢次下載重複的庫。許多狀況下都是這樣網絡換取速度。
Webpack 實際上有它本身的開發服務器,所以不管你正在開發一個靜態頁面或者作前端原型,它都很是適合。你能夠增長一個devServer
對象 在 webpack.config.js
module.exports = {
context: path.resolve(__dirname, './src'),
entry: {
app: './app.js',
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './dist/assets'),
publicPath: '/assets', // New
},
devServer: {
contentBase: path.resolve(__dirname, './src'), // New
},
};
在src/index.html
增長下面代碼:
<script src="/assets/app.bundle.js"></script>
終端裏面運行
webpack-dev-server
你的服務器已經運行在8080端口上。請注意在scipt標籤裏面的 /assets
,它匹配的是output對象裏面的publicPath(相似於express裏面的靜態目錄),你能夠任意命名,這一點在cdn加速的時候特別有用。
要用全局命名空間裏面的特定函數?在webpack.config.js
裏面配置output.library
module.exports = {
output: {
library: 'myClassName',
}
};
…這會在window對象上綁定一個myClassName的實例,如今在入口文件裏面能夠調用這個實例裏面的方法,或者值。
到目前爲止,咱們用到的語言僅僅是javascript, 這是必要的由於Webpack使用的惟一語言就是它 webpack自身只能處理javascript模塊。可是其餘類型的模塊和文件(好比sass,css)webpack自身沒有辦法處理,可是隻要咱們將它們通過javascript處理
一次轉換成咱們須要的類型。咱們就就它加載器或者轉換器。
加載器能夠扮演預處理的角色(編譯sass),或者轉換角色(好比babel,將es6或者React 轉換到es5),在npm上,一般他們以 *-loader
的方式命名,好比前面的 sass-loader
和 babel-loader
因爲如今es6兼容性問題,咱們想使用es6的特性就得須要babel的轉換了,首先咱們要安裝合適的加載(轉換)器:
yarn add --dev babel-loader babel-core babel-preset-es2015
…而後在webpack.config.js
下面配置
module.exports = {
// …
module: {
rules: [
{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: { presets: ['es2015'] }
}],
},
// Loaders for other file types can go here
],
},
// …
};
對於webpack 1.x
的用戶來講, 加載器的核心概念和2.x來講是一致的。可是語法有一些變化(好比1.x
中是loaders 而不是rules),由於如今仍然處於發佈候選版階段,因此在正式版文檔以前這些語法可能都不是最準確和合適的。
test
的正則對象 /\.js$/
的目的是去尋找babel-loder去加載的全部以.js結尾的文件。Webpack經過這個正則容許開發者去控制那些文件能夠被轉換或者編譯,固然他不會強制你採用那些文件擴展名,只須要你以合適的方式組織你的文件,這個正則匹配到了就好。
好比:在/my_legacy_code/
這個目錄下面,你沒有使用es6,你能夠修改上面test的值 /^((?!my_legacy_code).)*\.js$/
,babel-loader 會過濾掉這個特殊的文件夾,轉換其餘的文件。
咱們也能夠經過css-loader引入css文件,好比咱們當前項目目錄有 index.js
文件,咱們能夠這樣導入
import styles from './assets/stylesheets/application.css';
固然直接這樣一句代碼是不行的,會報錯:You may need an appropriate loader to handle this file type
,記住webpack只能解析javascript,所以咱們要安裝合適的loader。
yarn add --dev css-loader style-loader
而後在webpack.config.js裏面配置
module.exports = {
// …
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
// …
],
},
};
加載器的執行順序是數組索引的逆序,這意味着先會運行css-loader,而後再是style-loader.
你會注意到在生產環境下,webpack在打包css的同時也會將css同時打包,style-loader
實際上作的實質性內容就是將你的css代碼寫入到html裏面的head
標籤裏面。雖然乍看一下以爲有點奇怪,可是慢慢的你會發現,那實際上是合理的。 試想,你確定作過這樣的優化,少向服務端發送一個請求–就節約了網絡請求的時間-若是你採用js加載dom的方式,本質上也就避免Flash of unstyled content
。(參考地址:https://en.wikipedia.org/wiki/Flash_of_unstyled_content)
你也會注意到,webpack會自動的將@import 隊列裏面css文件打包成一個(並不是像css默認的importy引入方式,它會增長更多的請求下降加載靜態資源的速度)
在js文件中加載css是很是棒的,由於你能以一種新的方式模塊化你的css。你能夠在button.js裏面引用button.css,這意味着若是button.js沒有被使用,那麼button.css裏面的樣式永遠不會出如今生產環境中。若是你很是推崇css組件模塊化這一套體系好比 SMACSS 或者BEM(參考地址:https://smacss.com/book/categorizing),你在編寫css與你和js的時候發現它的精妙所在。
想使用sass,沒問題
yarn add --dev sass-loader node-sass
增長以下規則:
module.exports = {
// …
module: {
rules: [
{
test: /\.(sass|scss)$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
]
}
// …
],
},
};
這樣在js文件中能夠經過import引入sass或者scss文件了。
若是你想將css打包進一個單獨的文件,而不是依賴bundle將樣式以style寫入在head
標籤裏面。咱們可使用webpack插件extract-text-webpack-plugin
來實現,打開app.js
import styles from './assets/stylesheets/application.css';
安裝這個插件到本地目錄
yarn add --dev extract-text-webpack-plugin@2.0.0-beta.4
在webpack.config.js
增長以下配置:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
// …
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
loader: 'css-loader?importLoaders=1',
}),
},
// …
]
},
plugins: [
new ExtractTextPlugin({
filename: '[name].bundle.css',
allChunks: true,
}),
],
};
在終端運行webpack -p
你會發如今output設置的目錄裏面生成了一個app.bundle.css
文件,這時候在html文件裏面增長link引入css文件,打開html,和預期的同樣。
翻譯自: https://blog.madewithenvy.com/getting-started-with-webpack-2-ed2b86c68783#.qdh8mzhl0
參考資料: https://webpack.js.org/configuration/