webpack-dev-server是一個小型的Node.js Express
服務器,它使用webpack-dev-middleware
來服務於webpack的包,除此自外,它還有一個通過Sock.js來連接到服務器的微型運行時.
我們來看一下下面的配置文件(webpack.config.js
)
var path = require("path"); module.exports = { entry:{ app:["./app/main.js"] }, output:{ path:path.resolve(__dirname,"build"), publicPath:"/assets/", filename:"bundle.js" } }
這里你將你的源文件放在app
文件夾下,並通過webpack
將其打包到build
文件夾下的bundle.js
中.
注意:webpack-dev-server
是一個獨立的NPM包,你可以通過npm install webpack-dev-server
來安裝它.
基本目錄
webpack-dev-server默認會以當前目錄為基本目錄,除非你制定它.
webpack-dev-server --content-base build/
上述命令是在命令行中執行的,它將build
目錄作為根目錄.有一點需要注意的是:webpack-dev-server生成的包並沒有放在你的真實目錄中,而是放在了內存中.
我們在基本目錄下新建一個index.html
文件,然后在瀏覽器中輸入http://localhost:8080
訪問.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script src="assets/bundle.js"></script> </body> </html>
webpack-dev-server啟動proxy代理
代理配置
webpack-dev-server使用http-proxy-middleware去把請求代理到一個外部的服務器,配置的樣例如下:
//配置服務器 devServer: { historyApiFallback: true, hot: true, inline: true, contentBase: "./app", port: 8090, proxy: { "/api": { target: 'http://localhost:8888', pathRewrite: {'^/api' : ''}, changeOrigin: true } }, },
這種代理在很多情況下是很重要的,比如你可以把一些靜態文件通過本地的服務器加載,而一些API請求全部通過一個遠程的服務器來完成。還有一個情景就是在兩個獨立的服務器之間進行請求分割,如一個服務器負責授權而另外一個服務應用本身。
pathRewrite: 對於代理的請求可以通過提供一個函數來重寫,這個函數可以查看或者改變http請求。下面的例子就會重寫HTTP請求,其主要作用就是移除URL前面的/api部分。
繞開代理
通過一個函數的返回值可以視情況的繞開一個代理。這個函數可以查看http請求和響應以及一些代理的選項。它必須返回要么是false要么是一個URL的path,這個path將會用於處理請求而不是使用原來代理的方式完成。下面的例子的配置將會忽略來自於瀏覽器的HTTP請求,他和historyApiFallback配置類似。瀏覽器請求可以像往常一樣接收到HTML文件,但是API請求將會被代理到另外的服務器:
proxy: { '/some/path': { target: 'https://other-server.example.com', secure: false, bypass: function(req, res, proxyOptions) { if (req.headers.accept.indexOf('html') !== -1) { console.log('Skipping proxy for browser request.'); return '/index.html'; } } } }
代理本地虛擬主機
http-proxy-middleware會預解析本地hostname成為localhost,你可以使用下面的配置來修改這種默認行為:
var server = new webpackDevServer(compiler, { quiet: false, stats: { colors: true }, proxy: { "/api": { "target": { "host": "action-js.dev", "protocol": 'http:', "port": 80 }, ignorePath: true, changeOrigin: true, secure: false } } }); server.listen(8080);
貼入我自己項目的webpack.config.js配置:
var webpack = require('webpack'); var path = require('path'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); //抽取CSS文件插件 var OpenBrowserPlugin = require('open-browser-webpack-plugin'); //自動打開瀏覽器插件 var ROOT_PATH = path.resolve(__dirname); var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); var APP_PATH = path.resolve(ROOT_PATH, 'app'); module.exports = { //配置服務器 devServer: { historyApiFallback: true, hot: true, inline: true, contentBase: "./app", port: 8090, proxy: { "/api": { target: 'http://localhost:8888', pathRewrite: {'^/api' : ''}, changeOrigin: true } }, }, //配置入口, 支持多入口 entry: { page: ROOT_PATH + '/app/src/router/router.jsx', vendors: ['react', 'react-dom', 'react-router', 'mobx'] //第三方庫和框架 }, output: { // path: "dist", publicPath: 'dist', filename: 'js/bundle.js' }, module: { loaders: [ { test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })//此處不用loader,改為use }, { test: /\.less$/, loader: ExtractTextPlugin.extract('css-loader!less-loader') }, { test: /\.js[x]?$/, exclude: /node_modules/, loader: 'babel-loader' }, { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192&name=img/[name].[ext]' }, { test: /\.(woff|woff2|eot|ttf|svg)(\?.*$|$)/, loader: 'url-loader' } ] }, resolve: { extensions: [' ', '.js', '.jsx'] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ 'name': 'vendors', 'filename': 'js/vendors.js' }), new ExtractTextPlugin("css/bundle.css"), // 如需jquery請解鎖 // new webpack.ProvidePlugin({ $: "jquery" }), new webpack.HotModuleReplacementPlugin(), new OpenBrowserPlugin({ url: 'http://localhost:8090/gallery' }) ] }
總結: 如有疑問請參考官方文檔 https://doc.webpack-china.org/concepts/