文章說明
這篇文章是在看阮一峰老師在GitHub上發表的webpack學習文件的時候,翻譯出的文件說明webpack 阮一峰教程 ,純手打非機翻。
最後兩個demo沒有打上來,翻譯好會補上來。文中有一小部分文字是我針對這個知識點的理解,就幾行。
如果有錯誤,歡迎指出。
再次感謝阮一峰老師。
什麼是webpack
前端構建工具,與gulp和grunt 類似
作為打包工具,與browserify 類似
# be equivalent to
$ webpack main.js bundle.js
複製程式碼
配置檔案是 webpack.config.js
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
複製程式碼
常見的命令們
- webpack 供開發構建
- webpack -p 供生產構建一次
- webpack --watch – 連續的增量構建
- webpack -d – 包括源地圖
- webpack --colors – 讓內部更好看
生產環境的應用需要在package.json中配置script :
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
複製程式碼
入口檔案
就是第一個進入的檔案,使用入口檔案進行打包或者構建 demo1中的bundle.js
在demo1 的例子中, main.js是入口檔案
複製程式碼
在index.html 中:
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack 會按照webpack.config.js 去構建 bundle.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
複製程式碼
使用命令webpack-dev-server
啟動伺服器
多入口檔案
對於多頁面網站,適合使用多個入口檔案
在main1.js 和main2.js 中
document.write('<h1>Hello World</h1>');
// main2.js
document.write('<h2>Hello Webpack</h2>');
複製程式碼
index.html 中
<html>
<body>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>
複製程式碼
在webpack.config.js 中
module.exports = {
entry: {
bundle1: './main1.js',
bundle2: './main2.js'
},
output: {
filename: '[name].js'
}
};
複製程式碼
babel-loader
loader 是前處理器,讓webpack處理非js檔案,將所有的檔案轉換為webpack能夠處理的有效模組
loader的兩個目標
- 識別出應該被loader轉化的檔案, 使用test屬性
- 轉換這些檔案,使他們新增到依賴圖中,最終新增到bundle中,使用use屬性
babel-loader 是一個將jsx、es6格式的檔案轉換為js檔案的工具。
在main.jsx中:
const ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.querySelector('#wrapper')
);
複製程式碼
在index.html 中
<body>
<div id="wrapper"></div>
<script src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
},
]
}
};
複製程式碼
在config.js中,module.loaders 用來分配loaders,上面的外掛使用了babel-loader,babel-preset-es2015,babel-preset-react 進行編譯,test用來檢測識別
還可以這樣寫
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
複製程式碼
css-loader
可以預處理css 檔案使用css—loader
main.js
require('./app.css');
複製程式碼
app.css
body {
background-color: blue;
}
複製程式碼
index.html
<html>
<head>
<script type="text/javascript" src="bundle.js"></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
複製程式碼
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.css$/, loader: 'style-loader!css-loader' },
]
}
};
複製程式碼
這裡需要注意到是,必須使用兩個載入器來轉換,css-loader 是用來讀取cssfile,style-loader是用來將style標籤插入到html頁面的,不同的loader使用‘!’來連線
image loader
同樣,圖片資源也可以在js 檔案中 main.js
var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);
var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);
複製程式碼
index.html
<html>
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
]
}
};
複製程式碼
url轉換image檔案,如果小於8192不用特殊,就可以轉化成資料url,不然的化就是正常的url。‘?’是用來給loader傳遞引數的
轉化之後的圖片如下:
<img src="data:image/png;base64,iVBOR...uQmCC">---小圖
<img src="4853ca667a2b8b8844eb2693ac1b2578.png"> ---大圖
複製程式碼
css模組
使用css-loader?modules
可以滿足css模組的需求
main.js
var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');
ReactDOM.render(
<div>
<h1 className={style.h1}>Hello World</h1>
<h2 className="h2">Hello Webpack</h2>
</div>,
document.getElementById('example')
);
複製程式碼
app.css
.h1 {
color:red;
}
:global(.h2) {
color: blue;
}
複製程式碼
index.html
<html>
<body>
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hello Webpack</h2>
<div id="example"></div>
<script src="./bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules'
}
]
}
};
複製程式碼
如果是css模組是行成自己的作用域?可以使用:global來進行開關 在上面的例子中只有第二個h1是紅色的,因為css被本地作用域化了,兩個h2都是藍的,因為是全域性的
uglify
webpack有很多管道系統來擴充套件他的功能,uglify是用來壓縮js程式碼的
main.js
var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');
複製程式碼
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new uglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
複製程式碼
使用plugins 來使用uglify,在exports的上面定義uglify
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;以及使用plugins 來使用uglify
載入第三方管道
html-webpack-plugin
能夠建立index.html.open-browser-webpack-plugin
能在webpack載入的時候開啟一個瀏覽器標籤頁
main.js
document.write('<h1>Hello World</h1>')
複製程式碼
index.html不需要寫了哈哈哈哈
webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos',
filename: 'index.html'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
};
複製程式碼
這個例子中可以看到我們不需要寫一個index.html 不需要我們自己開啟瀏覽器,webpack做好了
environment tag
main.js
document.write('<h1>Hello World</h1>');
if (__DEV__) {
document.write(new Date());
}
複製程式碼
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
var webpack = require('webpack');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [devFlagPlugin]
};
複製程式碼
如果我們使用下面這行程式碼將環境變數設定為true,可以看到了日期
$ env DEBUG=true webpack-dev-server
複製程式碼
程式碼分割code spliting
相對於大型的app來說,所有的程式碼放到一個單獨的檔案會導致低效率的,webpack提供拆分成塊的這種機制, 尤其是在某些條件小才會有需求的程式碼塊,這些程式碼塊應該在需要的時候載入,不需要的時候就不載入
使用require.ensure 來定義一個拆分點,用來告訴webpack 這個./a.js應該從bundle.js 中拆分,並且生成一個單獨的檔案
main.js
// main.js
require.ensure(['./a'], function(require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
複製程式碼
a.js
module.exports = 'Hello World';
複製程式碼
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
複製程式碼
web.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
複製程式碼
在執行的時候,其實webpack構建了兩個塊,bundle.js 和 1.bundle.js(來自a.js),只有在需要的時候載入1.bundle.js
bundle loader and code splitting
另一種程式碼拆分的方式是使用bundle-loader
在main.js 檔案中
// 現在我們需要a.js了,將會繫結在另一個檔案中
// 下面這句是告訴webpack 從別的塊中載入a.js
var load = require('bundle-loader!./a.js');
// 等待a.js可用的時候,我們就能獲取到這個exports
// 可以使用非同步來等待
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
複製程式碼
common chunk
當多個script有公共的程式碼塊時候, 我們希望把這個抽取出來行成一個獨立的檔案。我們可以使用commonschunkplugin來實現這個功能
例如下面的main1.jsx和main2.jsx
// main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('a')
);
// main2.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h2>Hello Webpack</h2>,
document.getElementById('b')
);
複製程式碼
index.html
<html>
<body>
<div id="a"></div>
<div id="b"></div>
<script src="init.js"></script>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
bundle1: './main1.jsx',
bundle2: './main2.jsx'
},
output: {
filename: '[name].js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
]
},
plugins: [
new CommonsChunkPlugin('init.js')
]
}
複製程式碼
三方程式碼塊 vendor chunk
使用Commonschunkplugin還可以實現吧script標籤內的三方庫抽取出形成一個單獨的檔案
例如jQuery
main.js
var $ = require('jquery');
$('h1').text('Hello World');
複製程式碼
index.html
<html>
<body>
<h1></h1>
<script src="vendor.js"></script>
<script src="bundle.js"></script>
</body>
</html>
複製程式碼
webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.js')
]
};
複製程式碼
commonchunkplugin中有兩個引數,第一個是抽取出的塊的名字,第二個是抽取出之後的檔案
如果想要讓某個模組全域性可用, 例如不使用require('jquery')卻可以全域性使用$和 jQuery, 可以使用ProvidePlugin來實現.
main.js
$('h1').text('Hello World');
複製程式碼
webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js'
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
};
複製程式碼
暴露全域性變數
data.js
var data = 'Hello World';
複製程式碼
使用externals來暴露全域性變數 // webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
]
},
externals: {
// require('data') is external and available
// on the global var data
'data': 'data'
}
};
複製程式碼
在externals屬性中data作為全域性變數在script中。
在main.jsx 中使用data:
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>{data}</h1>,
document.body
);
複製程式碼