Webpack 是什麼css
https://github.com/webpackhtml
Webpack 是德國開發者 Tobias Koppers 開發的模塊加載器,Instagram 工程師認爲這個方案很棒, 彷佛還把做者招過去了。前端
在 Webpack 當中, 全部的資源都被看成是模塊, js, css, 圖片等等。所以, Webpack 當中 js 能夠引用 css, css 中能夠嵌入圖片 dataUrl。node
對應各類不一樣文件類型的資源, Webpack 有對應的模塊 loader。好比 CoffeeScript 用的是 coffee-loader, 其餘還有不少:http://webpack.github.io/docs/list-of-loaders.htmlreact
大體的寫法也就這樣子:jquery
module: {
loaders: [
{ test: /\.coffee$/, loader: 'coffee-loader' },
{ test: /\.js$/, loader: 'jsx-loader?harmony' } // loaders can take parameters as a querystring
]
},
CommonJS 與 AMD 支持webpack
Webpack 對 CommonJS 的 AMD 的語法作了兼容, 方便遷移代碼。不過實際上, 引用模塊的規則是依據 CommonJS 來的git
require('lodash') // 從模塊目錄查找
require('./file') // 按相對路徑查找
AMD 語法中, 也要注意, 是按 CommonJS 的方案查找的github
define (require, exports. module) ->
require('lodash') # commonjs 當中這樣是查找模塊的
require('./file')
特殊模塊的 Shimweb
好比某個模塊依賴 window.jQuery, 須要從 npm 模塊中將 jquery 掛載到全局。Webpack 有很多的 Shim 的模塊, 好比 expose-loader 用於解決這個問題:https://github.com/webpack/docs/wiki/shimming-modules
其餘好比從模塊中導出變量...具體說明有點晦澀..
手頭的兩個例子, 好比咱們用到 Pen 這個模塊, 這個模塊對依賴一個 window.jQuery, 可我手頭的 jQuery 是 CommonJS 語法的,而 Pen 對象又是生成好了綁在全局的, 但是我又須要經過 require('pen') 獲取變量。 最終的寫法就是作 Shim 處理直接提供支持:
{test: require.resolve('jquery'), loader: 'expose?jQuery'},
{test: require.resolve('pen'), loader: 'exports?window.Pen'},
基本的使用
安裝 webpack 模塊以後, 但是使用 webpack 這個命令行工具。可使用參數, 也能夠配置 webpack.config.js 文件直接運行 webpack 調用。 建議按照 Peter Hunt 給的教程走一遍, 基本的功能都會用到了:https://github.com/petehunt/webpack-howto
簡單的例子就是這樣一個文件, 能夠把 ./main.js 做爲入口打包 bundle.js:
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
查找依賴
Webpack 是相似 Browserify 那樣在本地按目錄對依賴進行查找的。能夠構造一個例子, 用 --display-error-details 查看查找過程, 例子中 resolve.extensions 用於指明程序自動補全識別哪些後綴, 注意一下, extensions 第一個是空字符串! 對應不須要後綴的狀況.
// webpack.config.js
module.exports = {
entry: './a.js',
output: {
filename: 'b.js'
},
resolve: {
extensions: ['', '.coffee', '.js']
}
}
// a.js
require('./c')
➤➤ webpack --display-error-details
Hash: e38f7089c39a1cf34032
Version: webpack 1.5.3
Time: 54ms
Asset Size Chunks Chunk Names
b.js 1646 0 [emitted] main
[0] ./a.js 15 {0} [built] [1 error]
ERROR in ./a.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./c in /Users/chen/Drafts/webpack/details
resolve file
/Users/chen/Drafts/webpack/details/c doesn't exist
/Users/chen/Drafts/webpack/details/c.coffee doesn't exist
/Users/chen/Drafts/webpack/details/c.js doesn't exist
resolve directory
/Users/chen/Drafts/webpack/details/c doesn't exist (directory default file)
/Users/chen/Drafts/webpack/details/c/package.json doesn't exist (directory description file)
[/Users/chen/Drafts/webpack/details/c]
[/Users/chen/Drafts/webpack/details/c.coffee]
[/Users/chen/Drafts/webpack/details/c.js]
@ ./a.js 2:0-14
./c 是不存在, 從這個錯誤信息當中咱們大體能瞭解 Webpack 是怎樣查找的。大概就是會嘗試各類文件名, 會嘗試做爲模塊, 等等。 通常模塊就是查找 node_modules, 但這個也是能被配置的:http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories
CSS 及圖片的引用
英文的教程上有明確的例子:
https://github.com/petehunt/webpack-howto#5-stylesheets-and-images
require('./bootstrap.css');
require('./myapp.less');
var img = document.createElement('img');
img.src = require('./glyph.png');
上邊的是 JavaScript 代碼, CSS 跟 LESS, 還有圖片, 被直接引用了。實際上 CSS 被轉化爲 <style> 標籤, 而圖片可能被轉化成 base64 格式的 dataUrl。 可是要主要在 webpack.config.js 文件寫好對應的 loader:
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
path: './build', // This is where images AND js will go
publicPath: 'http://mycdn.com/', // This is used to generate URLs to e.g. images
filename: 'bundle.js'
},
module: {
loaders: [
{ test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, // use ! to chain loaders
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} // inline base64 URLs for <=8k images, direct URLs for the rest
]
}
};
url-loader
稍微囉嗦一下這個 loader, 這個 loader 其實是對 file-loader 的封裝https://github.com/webpack/url-loader
好比 CSS 文件當中有這樣的引用:
.demo {
background-image: url('a.png');
}
那麼對應這樣的 loader 配置就能把 a.png 抓出來, 而且按照文件大小, 或者轉化爲 base64, 或者單獨做爲文件:
module: {
loaders: [
{test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} // inline base64 URLs for <=8k images, direct URLs for the rest
]
}
上邊 ? 後邊的 query 有兩種寫法, 能夠看下文檔: http://webpack.github.io/docs/using-loaders.html#query-parameters
file-loader
因爲 url-loader 是對 file-loader 的一個封裝, 以所以帶有後者一些功能: https://github.com/webpack/file-loader
好比說, file-loader 有不弱的定義文件名的功能
require("file?name=[path][name].[ext]?[hash]!./dir/file.png")
對應 url-loader 當中若是文件超出體積, 就給一個這樣的文件名..
打成多個包
有時考慮類庫代碼的緩存, 咱們會考慮打成多個包, 這樣不難。好比下邊的配置, 首先 entry 有多個屬性, 對應多個 JavaScript 包, 而後 commonsPlugin 能夠用於分析模塊的共用代碼, 單獨打一個包出來:
https://github.com/petehunt/webpack-howto#8-optimizing-common-code
https://github.com/webpack/docs/wiki/optimization#multi-page-app
// webpack.config.js
var webpack = require('webpack');
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
module.exports = {
entry: {
Profile: './profile.js',
Feed: './feed.js'
},
output: {
path: 'build',
filename: '[name].js' // Template based on keys in entry above
},
plugins: [commonsPlugin]
};
對文件作 revision
這個在文檔上作了說明, 能夠自動生成 js 文件的 Hash:
http://webpack.github.io/docs/long-term-caching.html
output: { chunkFilename: "[chunkhash].bundle.js" }
plugins: [
function() {
this.plugin("done", function(stats) {
require("fs").writeFileSync(
path.join(__dirname, "...", "stats.json"),
JSON.stringify(stats.toJson()));
});
}
]
同時, 能夠註冊事件, 拿到生成的帶 Hash 的文件的一個表。可是拿到那個表以後, 就須要本身寫代碼進行替換了.. 這有點麻煩。 官網的 Issue 裏提到個辦法是生成 HTML 時引用 stats.json 的數據, 我此前的方案是生成 HTML 以後再進行替換, 相對賴上生成時寫入更好一些。
上線
另外一份配置文件
用 webpack --config webpack.min.js 指定另外一個名字的配置文件,這個文件當中能夠寫不同配置, 專門用於代碼上線時的操做。
壓縮 JavaScript
由於代碼都是 JavaScript, 因此壓縮就很簡單了, 加上一行 plugin 就行了http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
plugins: [
new webpack.optimize.MinChunkSizePlugin(minSize)
]
壓縮 React
React 官方提供的代碼是已經合併的, 這個是 Webpack 不推薦的用法, 在合併話的代碼上進行定製有點麻煩, Webpack 提供了設置環境變量來優化代碼的方案:
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("production")
}
})
https://github.com/webpack/webpack/issues/292#issuecomment-44804366
CDN
替換 CDN 這個工做, Webpack 也內置了, 設置 output.publicPath 便可http://webpack.github.io/docs/configuration.html#output-publicpath
代碼熱替換
雖然文檔上寫得挺複雜的, 但若是隻是簡單的功能仍是很容易的。
第一步, 把 'webpack/hot/dev-server' 加入到打包的代碼當中, 這個是對應 node_modules/webpack/ 目錄當中的文件的:
entry: { main: ['webpack/hot/dev-server', './main'], vendor: ['lodash', './styles'] },
啓動服務器, 好比我是這樣子的
webpack-dev-server --hot --quiet
正常能夠看到提示說服務器已經起來了。http://localhost:8080/webpack-dev-server/
若是有 index.html 的話, 直接訪問網址應該就能開始調試了。
React Hot Replace
調試 React 的話, 有這樣的工具簡直是神器了, 甚至不用刷新頁面!
http://gaearon.github.io/react-hot-loader/getstarted/
entry: [
'webpack-dev-server/client?http://0.0.0.0:8080', // WebpackDevServer host and port
'webpack/hot/only-dev-server',
'./scripts/index' // Your appʼs entry point
]
我特地問了下做者爲何上邊配置看起來不同..
https://github.com/gaearon/react-hot-loader/issues/73#issuecomment-73679446
回覆大體說是爲了不自動的強制刷新他用了特別的寫法..
關於這項功能具體如何實現, 我沒有深刻了解過...
hot replace 非靜態的網頁
上邊 localhost:8080 的方案並不適合複雜的頁面, 因而文檔上給出了一套稍微複雜一些的方案, 用來配合其餘的服務器調試。 大體的思路是這樣的:
Webpack 打包生成的那些靜態資源用服務器 A 進行 serve
這裏說的 A 就是上邊說的這個:
webpack-dev-server --hot --quiet
咱們的 HTML 由 B 渲染, B 會引用 A serve 的靜態資源B 生成的頁面當中加上相似這樣的代碼:
<script src="http://<A 的地址>/assets/bundle.js">
還可能要設置一下 output.publicPath, 把全部靜態資源指向 A
文件修改時, webpack-dev-server 經過 socket.io 通知客戶端更新
這個步驟在文檔上寫得有點難懂, 大概要多嘗試幾回才行, 我也弄錯不少次 http://webpack.github.io/docs/webpack-dev-server.html
單獨打包 CSS
由於公司裏有這個須要求, 強制把 CSS 從 js 文件當中獨立出來。 官方文檔是以插件的形式作的: http://webpack.github.io/docs/stylesheets.html#separate-css-bundle
參考文檔可是注意一下函數參數, 第一第二個參數是有區別的, 好比這樣用:
ExtractTextPlugin.extract('style-loader', 'css!less')
第一個參數是編譯好之後的代碼用的, 第二個參數是編譯到源代碼用的.. 有點難懂..
感想
Webpack 的報錯挺不友好的, 最初的時候我看着模塊找不到無法搞明白,這種時候把中間過程打印出來看是不錯的選擇:
webpack --display-error-details
另外一個報錯是沒有對應 loader 的提示.. log 可能很長找不到重點。我建議是先本身去想一想什麼地方須要考慮 loader 吧... 可能就知道了。 我還遇到就是源碼裏有使用 dataUrl 致使報錯... 確實奇怪了。
不說這些坑的話, Webpack 我認爲是我目前接觸到最好的前端開發方案,不少功能以前 FIS 文檔上看到過, 但 FIS 相對重一些我始終沒上手。而 Webpack 一上來就繞過了此前公司用 RequireJS 打包時遇到的各類問題。
建議去掃 Webpack 的文檔, 還有不少功能我徹底沒涉及到..http://webpack.github.io/docs/