模塊依賴(lài),一招搞定
require("./lib.js");require("./style.css");require("./style.less");require("./template.jade");require("./image.png");
在 Webpack 當(dāng)中, 所有的資源都被當(dāng)作是模塊。
對(duì)應(yīng)各種不同文件類(lèi)型的資源,Webpack有對(duì)應(yīng)的模塊loader
module: { //加載器配置 loaders: [ //.css 文件使用 style-loader 和 css-loader 來(lái)處理 { test: /\.css$/, loader: 'style-loader!css-loader' }, //.js 文件使用 jsx-loader 來(lái)編譯處理 { test: /\.js$/, loader: 'jsx-loader?harmony' }, //.scss 文件使用 style-loader、css-loader 和 sass-loader 來(lái)編譯處理 { test: /\.scss$/, loader: 'style!css!sass?sourceMap'}, //圖片文件使用 url-loader 來(lái)處理,小于8kb的直接轉(zhuǎn)為base64 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ]}
以 AMD/CMD 模式來(lái)說(shuō),鑒于模塊是異步加載的,所以我們常規(guī)需要使用 define 函數(shù)來(lái)幫我們搞回調(diào):
define(['package/lib'], function(lib){ function foo(){ lib.log('hello world!'); } return { foo: foo };});
另外為了可以兼容 commonJS 的寫(xiě)法,我們也可以將 define 這么寫(xiě):
define(function (require, exports, module){ var module1 = require("module1"); var module2 = require("module2"); module1.sayHello(); module2.sayHi(); exports.helloWorld = function (){ module1.sayHello(); module2.sayHi(); };});
然而對(duì) webpack 來(lái)說(shuō),我們可以直接在上面書(shū)寫(xiě) commonJS 形式的語(yǔ)法,無(wú)須任何 define (畢竟最終模塊都打包在一起,webpack 也會(huì)最終自動(dòng)加上自己的加載器):
var module1 = require("module1");var module2 = require("module2"); module1.sayHello();module2.sayHi();exports.helloWorld = function (){ module1.sayHello(); module2.sayHi();};
不過(guò)即使你保留了之前 define 的寫(xiě)法也是可以滴,畢竟 webpack 的兼容性相當(dāng)出色,方便你舊項(xiàng)目的模塊直接遷移過(guò)來(lái)。
首先確保機(jī)子上已安裝node.js,然后通過(guò)npm安裝webpack
npm install webpack -g
切換到有 webpack.config.js 的目錄然后運(yùn)行
webpack // 執(zhí)行一次開(kāi)發(fā)的編譯webpack -p // 針對(duì)發(fā)布環(huán)境編譯(壓縮代碼)webpack -w // 進(jìn)行開(kāi)發(fā)過(guò)程持續(xù)的增量編譯(飛快地!)webpack -d // 生成map映射文件,告知哪些模塊被最終打包到哪里了webpack --config XXX.js //使用另一份配置文件(比如webpack.config2.js)來(lái)打包
所有的加載器都需要通過(guò) npm 來(lái)加載,并建議查閱它們對(duì)應(yīng)的 readme 來(lái)看看如何使用
npm install url-loader --save-dev
如果目錄沒(méi)有package.json,則需要先init一下,再運(yùn)行npm install
命令
npm initnpm install url-loader --save-dev
每個(gè)項(xiàng)目下都必須配置有一個(gè) webpack.config.js
// webpack.config.jsvar webpack = require('webpack');var commonsPlugin = new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'common', /* filename= */'common.js'); // 分析以下模塊的共用代碼, 單獨(dú)打一個(gè)包到common.jsvar ExtractTextPlugin = require("extract-text-webpack-plugin"); // 單獨(dú)打包CSSvar HtmlWebpackPlugin = require('html-webpack-plugin'); // Html文件處理module.exports = { entry: { Detail: './modules/app/detail.js', Home: './modules/app/home.js' }, output: { path: './build', // This is where images & js will go //publicPath: 'http://m.pp.cn/ppaweb/test/build/', // This is used to generate URLs to e.g. images publicPath: '/ppaweb/example/build/', // This is used to generate URLs to e.g. images filename: '[name].js', chunkFilename: "[id].chunk.js?[hash:8]" }, plugins: [ commonsPlugin, new ExtractTextPlugin('[name].css', {allChunks: true}), // 單獨(dú)打包CSS // 全局變量 new webpack.DefinePlugin({ //__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV||'false')) //通過(guò)環(huán)境變量設(shè)置 __DEV__: 'false' // 開(kāi)發(fā)調(diào)試時(shí)把它改為true }), /** * HTML文件編譯,自動(dòng)引用JS/CSS * * filename - 輸出文件名,相對(duì)路徑output.path * template - HTML模板,相對(duì)配置文件目錄 * chunks - 只包含指定的文件(打包后輸出的JS/CSS),不指定的話(huà),它會(huì)包含生成的所有js和css文件 * excludeChunks - 排除指定的文件(打包后輸出的JS/CSS),比如:excludeChunks: ['dev-helper'] * hash */ new HtmlWebpackPlugin({filename: 'views/home.html', template: 'views/home.html', chunks: ['common', 'Home'], hash: true}), new HtmlWebpackPlugin({filename: 'views/detail.html', template: 'views/detail.html', chunks: ['common', 'Detail'], hash: true}) ], module: { loaders: [ { test: /\.js$/, loader: 'babel-loader', // ES6 exclude: /(node_modules|bower_components|ppaweb\\libs\\webpack)/ }, // CSS,LESS打包進(jìn)JS { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, // use ! to chain loaders // CSS,LESS單獨(dú)打包 //{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, //{ test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader') }, { test: /\.tpl$/, loader: 'ejs'}, // artTemplate/ejs 's tpl { test: /\.(png|jpg|gif)$/, loader: 'url-loader', query: { name: '[path][name].[ext]?[hash:8]', limit: 8192 // inline base64 URLs for <=8k images, direct URLs for the rest } } ] }, resolve: { alias: { 'lib0': '../../../ppaweb/libs/webpack', // 從module調(diào)用webpack上的公共lib庫(kù)路徑簡(jiǎn)寫(xiě) 'lib1': '../../../../ppaweb/libs/webpack', // 從module的子文件夾調(diào)用webpack上的公共lib庫(kù)路徑簡(jiǎn)寫(xiě) 'lib2': '../../../../../ppaweb/libs/webpack' // 從module的兩層子文件夾調(diào)用webpack上的公共lib庫(kù)路徑簡(jiǎn)寫(xiě) }, // 現(xiàn)在可以寫(xiě) require('file') 代替 require('file.coffee') extensions: ['', '.js', '.json', '.coffee'] }};
具體可以參考:webpack-demo的配置項(xiàng)
require('./bootstrap.css');require('./myapp.less');var img = document.createElement('img');img.src = require('./glyph.png');
module: { loaders: [ //圖片文件使用 url-loader 來(lái)處理,小于8kb的直接轉(zhuǎn)為base64 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ]}
background-image: url("./logo.png");
根據(jù)配置“url-loader?limit=xxx”來(lái)決定把圖片轉(zhuǎn)換成base64還是圖片鏈接形式引用。
module: { loaders: [ //圖片文件使用 url-loader 來(lái)處理,小于8kb的直接轉(zhuǎn)為base64 { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'} ]}
LESS里可以通過(guò)@import mixin.less
進(jìn)行模塊化開(kāi)發(fā),可以在import的路徑前面加上~,表示路徑以模塊處理,支持alias。
tnpm i @ali/pp-libs --save-dev
# index.less@import '@ali/pp-libs/libs/base/reset.less';
有時(shí)候可能希望項(xiàng)目的樣式能不要被打包到腳本中,而是獨(dú)立出來(lái)作為.css,然后在頁(yè)面中以標(biāo)簽引入。這時(shí)候我們需要 extract-text-webpack-plugin
來(lái)幫忙。
只需兩步:
npm install extract-text-webpack-plugin --save-dev
var ExtractTextPlugin = require("extract-text-webpack-plugin");……plugins: [ // 目標(biāo)文件名規(guī)則[name].css new ExtractTextPlugin('[name].css', {allChunks: true})],module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, { test: /\.less$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader') }, ]},
提取多個(gè)頁(yè)面之間的公共模塊,并將該模塊打包為 common.js
A.js, B.js => a.js, b.js, common.js
// 分析以下模塊的共用代碼, 單獨(dú)打一個(gè)包到common.jsvar commonsPlugin = new webpack.optimize.CommonsChunkPlugin(/*chunkName=*/'common', /*filename=*/'common.js');plugins: [ commonsPlugin],
記得要在HTML手動(dòng)引入common.js
上面是自動(dòng)在所有入口的js中提取公共代碼,并打包為common.js。
有時(shí)候我們希望能更加個(gè)性化一些,比如我希望:
A.js+C.js => AC-common.js
B.js+D.js => BD-common.js
我們可以這樣配:
module.exports = { entry: { A: "./a.js", B: "./b.js", C: "./c.js", D: "./d.js", E: "./e.js" }, output: { filename: "[name].js" }, plugins: [ new CommonsChunkPlugin("AC-commons.js", ["A", "C"]), new CommonsChunkPlugin("BD-commons.js", ["B", "D"]) ]};// <script>s required:// a.html: AC-commons.js, A.js// b.html: BD-commons.js, B.js// c.html: AC-commons.js, C.js// d.html: BD-commons.js, D.js// e.html: E.js
有時(shí)候我們連HTML里的JS/CSS資源都懶的寫(xiě),也是可行的,HTML也可以當(dāng)成模塊來(lái)寫(xiě)。
npm install html-webpack-plugin --save-dev
var HtmlWebpackPlugin = require('html-webpack-plugin'); // Html文件處理module.exports = { …… plugins: [ /** * HTML文件編譯,自動(dòng)引用JS/CSS * * filename - 輸出文件名,相對(duì)路徑output.path * template - HTML模板,相對(duì)配置文件目錄 * chunks - 只包含指定的文件(打包后輸出的JS/CSS),不指定的話(huà),它會(huì)包含生成的所有js和css文件 * excludeChunks - 排除指定的文件(打包后輸出的JS/CSS),比如:excludeChunks: ['dev-helper'] * hash */ new HtmlWebpackPlugin({filename: 'views/list.html', template: 'src/modules/app/list/index.html', chunks: ['common', 'List'], hash: true}), new HtmlWebpackPlugin({filename: 'views/detail.html', template: 'src/modules/app/detail/index.html', chunks: ['common', 'Detail'], hash: true}) ],};
有些代碼我們只想在開(kāi)發(fā)環(huán)境使用(比如log),這里,我們需要用到全局變量插件:webpack.DefinePlugin
module.exports = { plugins: [ // 全局變量 new webpack.DefinePlugin({ // __DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false')), //通過(guò)環(huán)境變量設(shè)置 __DEV__: JSON.stringify(JSON.parse('true')), // 開(kāi)發(fā)調(diào)試時(shí)把它改為true __HELLO__: JSON.stringify('hello world') }) ]};
js中調(diào)用
if(__DEV__) { console.log(__HELLO__);}
注意:webpack -p 會(huì)執(zhí)行 uglify dead-code elimination, 任何這種代碼都會(huì)被剔除, 所以你不用擔(dān)心秘密功能泄漏.
require.ensure
語(yǔ)法:
require.ensure(dependencies: String[], callback: function([require]), [chunkName: String])
與require AMD類(lèi)似,也是在需要的時(shí)候才會(huì)加載相應(yīng)的模塊。但不同的是,require.ensure在模塊被下載下來(lái)后(模塊還沒(méi)被執(zhí)行)便立即執(zhí)行回調(diào)函數(shù).另外require.ensure可以指定構(gòu)建后chunk名,如果之前已有require.ensure指定了該名稱(chēng),webpack會(huì)將這些模塊統(tǒng)一合并到一個(gè)模塊集里。
簡(jiǎn)單例子
// 異步加載if(i < 0) { require.ensure([], function() { require('a.js'); });}
定義異步加載文件名字(webpack.config.js)
output: { chunkFilename: "[id].chunk.[hash:8].js"},
生成的異步文件引用邏輯自動(dòng)包含在源目標(biāo)JS中,不用手動(dòng)引用,所以以上文件名隨便怎么定義都不影響。
圖片加載器url-loader其實(shí)是對(duì)file-loader的一個(gè)封裝
loaders: [ { test: /\.(png|jpg|gif)$/, loader: 'url-loader', query: { name: '[path][name].[ext]?[hash:8]', limit: 8192 } }]
如果文件超出體積, 就給一個(gè)這樣規(guī)則的文件名
參考:https://github.com/webpack/file-loader
module: { loaders: [ { test: /\.js$/, loader: 'babel-loader', // ES6 exclude: /(node_modules|bower_components|ppaweb\\libs\\webpack)/ }, ]},
參考:http://npm.taobao.org/package/babel-loader
webpack允許配置路徑的別名,這樣在一些外部資源的依賴(lài)的時(shí)候顯得格外有用,對(duì)以后的項(xiàng)目遷移等都起到不小的作用。
resolve: { alias: { // 從module調(diào)用公共libs上的庫(kù)路徑簡(jiǎn)寫(xiě) 'lib0': '../../../libs', // 從module的子文件夾調(diào)用公共libs上的庫(kù)路徑簡(jiǎn)寫(xiě) 'lib1': '../../../../libs', // 從module的兩層子文件夾調(diào)用公共libs上的庫(kù)路徑簡(jiǎn)寫(xiě) 'lib2': '../../../../../libs' }}
# module/index.jsrequire('lib0/proxy');# module/app/index.jsrequire('lib1/proxy');# module/app/header/index.jsrequire('lib2/proxy');
在 AMD/CMD 中,我們需要對(duì)不符合規(guī)范的模塊(比如一些直接返回全局變量的插件)進(jìn)行 shim 處理,這時(shí)候我們需要使用 exports-loader 來(lái)幫忙:
{ test: require.resolve("./src/js/tool/swipe.js"), loader: "exports?swipe"}
之后在腳本中需要引用該模塊的時(shí)候,這么簡(jiǎn)單地來(lái)使用就可以了:
require('./tool/swipe.js');swipe();
externals使用場(chǎng)景是外部依賴(lài)不需要打包進(jìn)bundle
比如:你在頁(yè)面里通過(guò)script標(biāo)簽引用了zepto:<script src="http://cdnjs.gtimg.com/cdnjs/libs/zepto/1.1.4/zepto.min.js"></script>
,所以并不想在其他js里再打包進(jìn)入一遍
// webpack.config.js...{ externals: { "zepto": "Zepto" // 引用時(shí)直接 var x = require('zepto'); }}
// index.jsvar $ = require('zepto');
編譯后會(huì)這樣
var $ = window.Zepto;
// var $ = require('zepto');// require('./index.less');!(function () { var module1 = (function () { var _e = {}; _e.test = function () { // do something here }; return _e; })(); window.module1 = module1; try { module.exports = module1; } catch (e) {}})();
模塊/組件一般會(huì)發(fā)布到NPM或者其他地方提供給他人使用的,這里可以使用libraryTarget字段來(lái)控制webpack打包后輸出為模塊/組件。
// webpack.config.jsmodule.exports = { entry: { pca: './src/main.js' }, output: { path: './dist', filename: '[name].js', libraryTarget: "umd" // 組件采用UMD格式打包 }, module: { loaders: [ { test: /\.js$/, loader: 'babel-loader', exclude: /(node_modules|libs)/ } ] }};
這樣,打包后發(fā)布到npm,別人就可以直接 npm install xxx
來(lái)安裝后,可以 var a = require('xxx');
來(lái)使用了。
一般一個(gè)頁(yè)面(HTML)對(duì)應(yīng)一個(gè)入口文件
/views/a.html/views/b.html/views/c.htmlentry: { A: 'modules/app/a.js', B: 'modules/app/b.js', C: 'modules/app/c.js'}
A. 插件html-webpack-plugin
聯(lián)系客服