npm install webpack -g 做爲全局安裝, 在任意目錄使用 npm install webpack --save-dev 做爲項目依賴安裝 npm init 建立package.json npm install webpack-dev-server --save-dev 使用webpack-dev-server啓動服務器 webpack --progress -colors 讓編譯的輸出內容帶有進度和顏色 webpack --watch 若是不想每次修改模塊後都從新編譯, 那麼能夠啓動監聽模式。 開啓監聽模式後, 沒有變化的模塊會在編譯後緩存到內存中, 而不會每次都被從新編譯, 因此監聽模式的總體速度是很快的 webpack --display-error-details 用來打印錯誤詳情 npm install xxx-loader --save-dev 安裝多個加載器: npm install babel-core babel-preset-es2015 babel-preset-react npm webpack --config webpack.config.js 執行打包命令 npm start 啓動開發模式下的server npm run start:prod 啓動生產模式的server npm run build 打包生產模式的代碼 npm run lint: eslint 代碼檢查 npm run lint:watch: eslint 監視 npm run remove:build 刪除dist目錄 npm run clean:build 清除dist目錄 // 調用webpack webpack 開發環境下編譯 webpack -p 產品編譯及壓縮 webpack --watch 開發環境下持續的監聽文件變更來進行編譯 webpack -d 引入source maps
webpack.config.dev.js: 開發模式相關配置 webpack.config.prod.js: 生產模式相關配置 server.js: 配置本地的server(包含dev server和prod server) 將server部分分離到一個單獨到的文件配置 package.json
//webpack.config.dev.js var webpack = require('webpack'); var path = require('path'); var config = { // 入口文件配置 entry: { path.resolve(__dirname, 'app/index.js'); }, // 文件輸出配置 output: { path: path.resolve(_dirname, 'build'), filename: 'bundle.js', publicPath: '/' }, // 插件項 plugins: [], // 加載器配置 module: { loaders: [ { test: /pattern/, loader: 'xxx-loader', exclude: /dir/, query: { presets: ['react'] } }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' // 內聯的base64的圖片地址, 圖片要小於8k, 直接的url的地址則不解析 } ] }, // 其餘解決方案配置 resolve: { extensions: ['', '.js', '.json'], alias: {} }, watch: true }; module.exports = config;
webpack.server.js var webpack = require('webpack'); var webpackServer = require('webpack-dev-server'); var config = require('./webpack.config.dev.js'); var compiler = webpack(config); var server = new webpackDevServer(compiler, { contentBase: './app', historyApiFallback: true, hot: true, //熱啓動 inline: true, // 監控js變化 stats: { color: true } }); config.entry.unshift('webpack-dev-server/client?http://localhost:8080/', 'webpack/hot/dev-server'); server.listen(8080, 'localhost', function(err) { if(err) { console.log(err); } console.log('Listening at localhost:8080...'); }); <!-- package.json --> 'script': { 'start': 'node server.js' }
entry: 入口, 定義要打包的文件 output: 出口, 定義打包輸出的文件;包括路徑, 文件名,還可能有運行時的訪問路徑(publicPath)參數 module: webpack將全部的資源都看作是模塊, 而模塊就須要加載器; |---- loaders: 主要定義一些loaders, 定義哪些後綴名的文件應該用哪些loader |-------- test: 匹配文件後綴, 檢測哪些文件須要此loader, 是一個正則表達式 |-------- exclude: 忽略哪些文件 |-------- query: 參數 (或直接寫於loader如: loader: 'url-loader?limit=8192') |------------ presets: resolve: 其餘解決方案配置 |---- extensions: 忽略文件擴展名, require文件時可直接使用require('file'),而非帶後綴如require('file.js') |-------- alias: 模塊別名定義,方便後續直接飲用別名無需多寫長地址, 後續直接require(key) plugins: 定義一些額外的插件 watch: 值爲boolean, 監聽文件變化
開發環境: webpack.config.dev.js 須要日誌輸出, sourcemap, 錯誤報告等 生產環境: webpack.config.prod.js 須要作代碼壓縮, 對文件名進行hash處理等
使用DefinePlugin設置環境變量, 根據設置的環境變量決定是否打包壓縮及啓動dev server或prod servercss
plugins: [ new webpack.DefinePlugin({ 'process.evn.NODE_ENV': JSON.stringify('production') }); ]
判斷當前是不是生產環境html
var isProduction = function() { return process.env.NODE_ENV === 'production'; } output: { path: path.resolve(isProduction ? '__build' : './assets/'), filename: isProduction ? '[name].js' : './assets/js/[chunkhash:8].[name].min.js', chunkFilename: isProduction ? '[chunkhash:8].chunk.js' : './assets/js/[chunkhash:8].chunk.min.js', publicPath: isProduction ? '/__build/' : 'http://cdn.site.com/' }
new webpack.optimizeUglifyJsPlugin({ compress: { warnings: false } });
對於沒有修改的文件, 從緩存中獲取文件, 對於已經修改的文件, 不要從緩存中獲取node
output: { //chunkhash 默認16位, 可自定義配置 filename: '[chunkhash:8].bundle.js' }
文件名帶上hash值後, 這個值在每次編譯的時候都會發生變化,都須要在 html 文件裏手動修改引用的文件名,這種重複工做很瑣碎且容易出錯, 這裏咱們能夠使用 html-webpack-plugin 來幫咱們自動處理這件事情, 用來簡化建立服務於webpackbundle的HTML文件react
解決方案: 在項目目錄下建一個index.tpl.html做爲鉤子jquery
<!-- index.tpl.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>My APP</title> </head> <body> <div id="app"></div> </body> </html>
在webpack.config.dev.js和webpack.config.prod.js添加配置代碼, 便可生成相應的index.htmlwebpack
plugins: [ new HtmlWebpackPlugin({ template: 'app/index.tpl.html', inject: 'body', filename: index.html }) ]
babel-loader: 轉換JSX babel-core: babel核心包 babel-preset-react babel-preset-es2015
<!-- webpack.config.dev.js --> <!-- babel-loader配置 --> loaders:[ { loaders: 'xxx-loader', query: { resets:['react', 'es2015'] } } ]
style-loader css-loader less-loader
url-loader 能夠根據自定義文件大小或者轉化爲 base64 格式的 dataUrl, 或者單獨做爲文件, 也能夠自定義對應的hash 文件名 file-loader 默認狀況下會根據圖片生成對應的 MD5hash 的文件格式 image-webpack-loader 提供壓縮圖片的功能
加載babel-loader須要配置query參數web
<!-- webpack.config.dev.js --> <!-- url-loader配置 --> loaders:[ { test: /\.(jpe?g|png|gif|svg)$/i, loaders: [ // 當內容size小於8KB時, 會自動轉成base64的方式內嵌進去, 這樣能夠減小一個HTTP的請求 // 當圖片大於8KB時, 則會在img/下生成壓縮後的圖片, 命名是[hash:8].[name].[ext]的形式 // hash:8的意思是取圖片內容hashsum值的前8位, // 這樣作可以保證引用的是圖片資源的最新修改版本, 保證瀏覽器端可以即時更新 'url?limit=8192&name=img/[hash:8].[name].[ext]', // 圖片壓縮 'image-webpack' ] } ]
<!-- webpack.config.dev.js --> <!-- file-loader配置 --> loaders:[ { test: /\.(jpe?g|png|gif|svg)$/i, loaders: [ // 生成md5 hash格式的文件名 'file?hash=sha512&digest=hex&name=[hash].[ext]', // 圖片壓縮 'image-webpack' ] } ]
<!-- webpack.config.dev.js --> plugins: [definPlugin, bannerPlugin, uglifyJsPlugin...]
var definPlugin = new webpack.DefinePlugin({ "process.env": { NODE_ENV: JSON.stringify("production") } // feature flags: 在開發環境(例如日誌)活內部測試環境(例如沒有發佈的新功能)中使用 // __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')), // __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false')) });
var bannerPlugin = new webpack.BannerPlugin('This is test!');
var uglifyJsPlugin = new webpack.optimize.UglifyJsPlugin({ mangle: { // 配置如下列表, 在混淆代碼時, 如下配置的變量, 不會被混淆 except: ['$super', '$', 'exports', 'require'] } });
var minChunkSizePlugin = new webpack.optimize.MinChunkSizePlugin({ compress: { warnings: false } });
var definPlugin = new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify('production') } });
new webpack.ProvidePlugin({ $: 'jquery' });
new webpack.optimize.CommonsChunkPlugin({ name: 'vendors', // 將公共模塊提取, 生成名爲`vendors`的chunk chunks: ['index','list','about'], //提取哪些模塊共有的部分 minChunks: 3 // 提取至少3個模塊共有的部分 });
new ExtractTextPlugin('css/[name].css'), // 相對於output配置中的publickPath
new HtmlWebpackPlugin({ //根據模板插入css/js等生成最終HTML favicon: './src/img/favicon.ico', //favicon路徑, 經過webpack引入同時能夠生成hash值 filename: './view/index.html', //生成的html存放路徑, 相對於path template: './src/view/index.html', //html模板路徑 inject: 'body', //js插入的位置, true/'head'/'body'/false hash: true, //爲靜態資源生成hash值 chunks: ['vendors', 'index'], //須要引入的chunk, 不配置就會引入全部頁面的資源 minify: { //壓縮HTML文件 removeComments: true, //移除HTML中的註釋 collapseWhitespace: false //刪除空白符與換行符 } });
new HtmlWebpackPlugin({ //根據模板插入css/js等生成最終HTML favicon: './src/img/favicon.ico', //favicon路徑, 經過webpack引入同時能夠生成hash值 filename: './view/list.html', //生成的html存放路徑, 相對於path template: './src/view/list.html', //html模板路徑 inject: true, //js插入的位置, true/'head'/'body'/false hash: true, //爲靜態資源生成hash值 chunks: ['vendors', 'list'], //須要引入的chunk, 不配置就會引入全部頁面的資源 minify: { //壓縮HTML文件 removeComments: true, //移除HTML中的註釋 collapseWhitespace: false //刪除空白符與換行符 } });
new webpack.HotModuleReplacementPlugin() // 熱加載 HotModuleReplacementPlugin() // 代碼熱替換 NoErrorsPlugin() // 報錯但不退出webpack進程 OpenBrowserPlugin() // 自動打開瀏覽器
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js'); module.exports = { entry: { page1: './main1.js', page2: './main2.js' }, output: { path: 'build', filename: '[name].js' }, plugins: [ commonsPlugin ] }
若是你但願在require文件時省略文件的擴展名, 只須要在webpack.config.js中添加 resolve.extensions
來配置。正則表達式
// webpack.config.js module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, module: { loaders: [ { test: /\.coffee$/, loader: 'coffee-loader' }, { test: /\.js$/, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } } ] }, resolve: { // 如今你require文件的時候能夠直接使用require('file'), 不用使用require('file.coffee') extensions: ['', '.js', '.json', '.coffee'] } };
首先你須要用require()
去加載你的靜態資源(named as they would with node's require()
):npm
require('./bootstrap.css'); require('./myapp.less'); var img = document.createElement('img'); img.src = require('./glyph.png');
當你require了CSS(less或者其餘)文件, webpack會在頁面中插入一個內聯的<style>
, 去引入樣式。當require圖片的時候, bundle文件會包含圖片的url, 並經過require()
返回圖片的url。json
可是這須要你在webpack.config.js
作相應的配置(這裏仍是使用loaders)
// webpack.config.js module.exports = { entry: './main.js', output: { path: './build', // 圖片和js會放在這 publicPath: 'http://mycdn.com/', // 這裏用來生成圖片的地址 filename: 'bundle.js' }, module: { loaders: [ { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' }, // 用!去鏈式調用loader { test: /\.css$/, loader: 'style-loader!css-loader' }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' // 內聯的base64的圖片地址, 圖片要小於8k, 直接的url的地址則不解析 } ] } };
項目中有些代碼咱們只爲在開發環境(例如日誌)或者是內部測試環境(例如那些沒有發佈的新功能)中使用, 那就須要引入下面這些魔法全局變量(magic globals):
if (__DEV__) { console.warn('Extra logging'); } // ... if (__PRERELEASE__) { showSecretFeature(); }
同時還要在webpack.config.js中配置這些變量, 使得webpack可以識別他們。
// webpack.config.js // definePlugin 會把定義的string 變量插入到Js代碼中。 var definePlugin = new webpack.DefinePlugin({ __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')), __PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false')) }); module.exports = { entry: './main.js', output: { filename: 'bundle.js' }, plugins: [definePlugin] };
配置完成後, 就能夠使用 BUILD_DEV=1 BUILD_PRERELEASE=1 webpack
來打包代碼了。
值得注意的是, webpack -p
會刪除全部無做用代碼, 也就是說那些包裹在這些全局變量下的代碼塊都會被刪除, 這樣就能保證這些代碼不會因發佈上線而泄露。
若是你有兩個頁面:profile和feed。若是你但願用戶訪問profile頁面時不加載feed頁面的代碼, 那就須要生成多個bundles文件:爲每一個頁面建立本身的「main module」(入口文件)。
// webpack.config.js module.exports = { entry: { Profile: './profile.js', Feed: './feed.js' }, output: { path: 'build', filename: '[name].js' // name是基於上邊entry中定義的key } };
在profile頁面中插入<script src="build/Profile.js"></script>
。feed也同樣。
Feed和Profile頁面存在大量通用代碼(好比React、公共的樣式和組件等等)。webpack能夠抽離頁面間公共的代碼, 生成一個公共的bundle文件, 供這兩個頁面緩存使用:
// 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' // 爲上面entry的key值 }, plugins: [commonsPlugin] };
在上一步引入本身的bundle以前引入<script src="build/common.js"></script>
雖然CommonJS是同步加載的, 可是webpack也提供了異步加載的方式。這對於單頁應用中使用的客戶端路由很是有用。當真正路由到了某個頁面的時候, 它的代碼纔會被加載下來。
指定你要異步加載的 拆分點。看下面的例子
if (window.location.pathname === '/feed') { showLoadingState(); require.ensure([], function() { // 這個語法痕奇怪, 可是仍是能夠起做用的 hideLoadingState(); require('./feed').show(); // 當這個函數被調用的時候, 此模塊是必定已經被同步加載下來了 }); } else if (window.location.pathname === '/profile') { showLoadingState(); require.ensure([], function() { hideLoadingState(); require('./profile').show(); }); }
剩下的事就能夠交給webpack, 它會爲你生成並加載這些額外的 chunk 文件。
webpack 默認會從項目的根目錄下引入這些chunk文件。你也能夠經過 output.publicPath
來配置chunk文件的引入路徑
// webpack.config.js output: { path: "/home/proj/public/assets", // webpack的build路徑 publicPath: "/assets/" // 你require的路徑 }