webpack簡述
按照webapck官網所說,webpack是一個模塊打包工具(webpack is a module bundler)。它接收依賴的模塊,將其轉化為靜態資源。
webpack與眾不同的三大核心概念
-
Code Spliting
-
Loaders
-
Plugin System
配置(configuration)
CLI
如果使用CLI,webpack將會讀取webpack.config.js文件(或者通過--config選項傳遞的文件),這個文件需要暴露這樣的配置對象:
module.exports = {
// configuration
};
常見CLI option
1)開發環境簡寫 -d
等價於:--debug --devtool source-map --output-pathinfo
2)生產環境簡寫 -p
等價於:--optimize-minimize --optimize-occurrence-order
3)監視模式 --watch
4)配置文件 --config example.config.js
指定新的配置文件,而不是默認的webpack.config.js
5)常見的顯示選項
- --progress
- --display-chunks
- --display-reasons
- --display-error-details
- --display-modules
- --display-exclude
可以通過script來定義腳本,然后npm run 命令名。
一個簡單的配置對象,注意不是json,只是簡單的object
{
context: __dirname + "/app",
entry: "./entry",
output: {
path: __dirname + "/dist",
filename: "bundle.js"
}
}
context
context:根目錄(絕對路徑!)。可以認為是文件查找的上下文。默認process.cwd()
entry
entry:包的入口點,有三種形式
-
一個string
-
一個由多個string構成的array
-
一個object(多頁面場景下),key是chunk的name,value可以是string或者array
output
output.filename
不要在這里指定絕對路徑
多入口情況下使用占位符
- [name] 模塊名稱
- [hash] 模塊編譯后的(整體)Hash值
- [chunkhash] 分片的Hash值,可以認為是文件的版本號,也可以認為是文件的MD5值,在靜態資源的版本管理中非常有用
output.path
output.publicPath
指定 public URL地址,當我們要將output的文件放在不同的域名或者CDN上時十分有用
module
module.loaders 一個自動應用的loaders的數組,每項(item)可以有這些屬性:
- test: A condition that must be met
- exclude: A condition that must not be met
- include: An array of paths or files where the imported files will be transformed by the loader
- loader: A string of “!” separated loaders
- loaders: An array of loaders as string
resolve
resolve.alias
模塊別名定義,方便后續直接引用別名
resolve: {
alias: { AppStore : 'js/stores/AppStores.js',//之后直接 require('AppStore')
}
}
resolve.root
包含你模塊的目錄(絕對路徑),也可以是一個目錄數組,這個設置應該被用於添加個人目錄到webpack查找路徑里
必須是個絕對路徑,不要這樣寫./app/modules
resolve.modulesDirectories
這是一個目錄數組,用來解析到當前目錄以及祖先目錄和查找模塊。這個函數的工作原理和node如何查找node_modules目錄很像。比如如果值為["mydir"],webpack會查找“./mydir”, “../mydir”, “../../mydir”等等
默認: ["web_modules", "node_modules"]
resolve.extensions
一個用來解析模塊的拓展名數組。比如,為了發現一個CoffeeScript文件,你的數組里應該包含字符串".coffee"
默認: ["", ".webpack.js", ".web.js", ".js"]
注意:設置這個選項將會重寫默認值
externals
指定不該被webpack打包的模塊,但是在打包后的包中仍然保留了請求。
我們可以通過它來暴露全局變量,而在需要的文件中直接require或import就可以了
externals: {
jquery: 'jQuery'
}
plugins
給編譯器添加額外的插件
各種loaders
webpack 可以使用 loader 來預處理文件。這允許你打包除 JavaScript 之外的任何靜態資源。你可以使用 Node.js 來很簡單地編寫自己的 loader。
loader的使用有三種方法,分別是:
- 在require中顯式指定,即上面看到的用法
- 在配置項(webpack.config.js)中指定
- 在命令行中指定
轉換ES6語法或React語法
通過presets選擇ES6特性,也可以在package.json中指定
解決babel-loader處理React的preset問題:npm i --save-dev babel-preset-react
2)css相關
- style-loader 將模塊的導出作為樣式添加到DOM中
- css-loader 解析CSS文件后,使用import加載,並且返回CSS代碼,可以在loader后面?modules以支持CSS Module
- less-loader 加載和轉譯LESS文件
- sass-loader 加載和轉譯SASS/SCSS文件,須先安裝node-sass,windows可能安裝出錯,使用cnpm i node-sass --save-dev或者如下:
npm install --save-dev node-sass --registry=https://registry.npm.taobao.org --disturl=https://npm.taobao.org/dist --sass-binary-site=http://npm.taobao.org/mirrors/node-sass
- postcss-loader 使用PostCSS加載和轉譯CSS/SSS文件,可以進行autoprefixer
CSS中@import另一個CSS怎么處理?(非SASS、LESS)
給css-loader添加參數
loader: 'style-loader!css-loader?importLoaders=1!postcss-loader'
3)模板相關
- html-loader 導出HTML為字符串,需要引用靜態資源
- jade-loader 加載Jade模板並返回一個函數
- markdown-loader 將Markdown轉譯為HTML
- handlebars-loader 將Handlebars轉換為HTML
- ejs-loader 將underscore模板轉換為HTML
4)圖片相關
- file-loader
- url-loader 與file-loader,但如果文件小於限制,可以返回 data URL
- image-loader 壓縮圖片
components模板引用相對路徑圖片不會替換?
可以使用絕對路徑或者這樣寫src="${require('../../assets/bg.png')}"
5)bundle-loader
bundle-loader是一個用來在運行時異步加載模塊的loader。可以用來做代碼分割
6)exports-loader
可以從模塊中導出變量。
在實際使用中,用exports-loader最多的場景是將某些不支持模塊化規范的模塊所聲明的全局變量作為模塊內容導出。
如下可以導出全局變量Hello,exports-loader還可以支持同時導出多個變量,例如exports?HELLO,WORLD
module.exports = {
module:{
loaders:[
{ test: require.resolve('./hello'), loader: "exports?Hello" }
]
}
};
7)imports-loaders
用於向一個模塊的作用域內注入變量(Can be used to inject variables into the scope of a module)
8)expose-loader
把一個模塊導出並付給一個全局變量
require("expose?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.
各種plugins
參數:
- template html模板地址,默認為webpack.config.js所在的目錄
- inject 插入位置
- title
- date等
2)CommonsChunkPlugin
將多個入口起點之間共享的公共模塊,生成為一些 chunk,並且分離到單獨的 bundle 中,例如,1vendor.bundle.js 和 app.bundle.js
3)ExtractTextWebpackPlugin
從 bundle 中提取文本(CSS)到分離的文件(app.bundle.css)
4)ProvidePlugin
ProvidePlugin可以將模塊作為一個變量,被webpack在其他每個模塊中引用。只有你需要使用此變量的時候,這個模塊才會被 require進來。多數之前遺留的模塊,會依賴於已存在的某些特定全局變量,比如jQuery插件中的$或者jQuery。在這種場景,你可以在每次遇到全局標識符$的時候,在webpack中預先設置var $ = require(“jquery”)。
module.exports = {
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
Environment flags
windows下使用cross-env的npm包兼容處理,可以在package.json設置如下:
"scripts": {
"clear": "rm -rf build&& mkdir build",
"start": "npm run clear&& cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --devtool eval --progress --color --profile",
"deploy": "npm run clear&& cross-env NODE_ENV=production webpack -p --progress"
}
webpack.config.js
var isProduction = process.env.NODE_ENV === 'production';
plugins: [new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}
})]
Code splitting(代碼分割)
使用require.ensure
// 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';
require.ensure告訴Webpack,./a.js應該從bundle.js分離並且打包成一個單獨的文件
注意require.ensure只會加載模塊而不會去解析
也可以用bundle-loader進行代碼分割
// main.js
// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');
// To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
vendor chunk
可以用CommonsChunkPlugin插件將公共庫(vendor)打包成一個單獨的文件
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')
]
};
模塊熱替換(Hot Module Replacement)
npm i webpack-dev-server --save-dev