Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webpack-dev-server使用方法,看完还不会的来找我~ #7

Open
CommanderXL opened this issue Jan 4, 2019 · 1 comment
Open
Labels

Comments

@CommanderXL
Copy link
Owner

记录下webpack-dev-server的用法.

首先,我们来看看基本的webpack.config.js的写法

    module.exports = {
        entry: './src/js/index.js',
        output: {
            path: './dist/js',
            filename: 'bundle.js'
        }
    }

配置文件提供一个入口和一个出口,webpack根据这个来进行js的打包和编译工作。虽然webpack提供了webpack --watch的命令来动态监听文件的改变并实时打包,输出新bundle.js文件,这样文件多了之后打包速度会很慢,此外这样的打包的方式不能做到hot replace,即每次webpack编译之后,你还需要手动刷新浏览器。

webpack-dev-server其中部分功能就能克服上面的2个问题。webpack-dev-server主要是启动了一个使用expressHttp服务器。它的作用主要是用来伺服资源文件。此外这个Http服务器client使用了websocket通讯协议,原始文件作出改动后,webpack-dev-server会实时的编译,但是最后的编译的文件并没有输出到目标文件夹,即上面配置的:

    output: {
        path: './dist/js',
        filename: 'bundle.js'
    }

注意:你启动webpack-dev-server后,你在目标文件夹中是看不到编译后的文件的,实时编译后的文件都保存到了内存当中。因此很多同学使用webpack-dev-server进行开发的时候都看不到编译后的文件

下面来结合webpack的文档和webpack-dev-server里部分源码来说明下如何使用:

##启动

启动webpack-dev-server有2种方式:

  1. 通过cmd line
  2. 通过Node.js API

##配置

我主要讲解下cmd line的形式,Node.js API形式大家去看下官方文档。可通过npm script进行启动。我的目录结构是:

    app
    |__dist
    |   |__styles
    |   |__js
    |       |__bundle.js
    |   |__index.html
    |__src
    |   |__styles
    |   |__js
    |       |__index.js
    |__node_modules
    |__package.json
    |__webpack.config.js

###content-base
设定webpack-dev-server伺服的directory。如果不进行设定的话,默认是在当前目录下。

webpack-dev-server --content-base ./dist

这个时候还要注意的一点就是在webpack.config.js文件里面,如果配置了outputpublicPath这个字段的值的话,在index.html文件里面也应该做出调整。因为webpack-dev-server伺服的文件是相对publicPath这个路径的。因此,如果你的webpack.config.js配置成这样的:

    module.exports = {
        entry: './src/js/index.js',
        output: {
            path: './dist/js',
            filename: 'bundle.js'
            publicPath: '/assets/'
        }
    }

那么,在index.html文件当中引入的路径也发生相应的变化:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Demo</title>
    </head>
    <body>
        <script src="assets/bundle.js"></script>
    </body>
    </html>

如果在webpack.config.js里面没有配置outputpublicPath的话,那么index.html最后引入的文件js文件路径应该是下面这样的。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Demo</title>
    </head>
    <body>
        <script src="bundle.js"></script>
    </body>
    </html>

##Automatic Refresh

webpack-dev-server支持2种自动刷新的方式:

  • Iframe mode
  • inline mode

这2种模式配置的方式和访问的路径稍微有点区别,最主要的区别还是Iframe mode是在网页中嵌入了一个iframe,将我们自己的应用注入到这个iframe当中去,因此每次你修改的文件后,都是这个iframe进行了reload

通过查看webpack-dev-server的源码,lib路径下的Server.js文件,第38-48行,分别新建几个流,这几个流保存了client文件夹下的相关文件:

	// Prepare live html page
	var livePage = this.livePage = new StreamCache();
	fs.createReadStream(path.join(__dirname, "..", "client", "live.html")).pipe(livePage);

	// Prepare the live js file
	var liveJs = new StreamCache();
	fs.createReadStream(path.join(__dirname, "..", "client", "live.bundle.js")).pipe(liveJs);

	// Prepare the inlined js file
	var inlinedJs = new StreamCache();
	fs.createReadStream(path.join(__dirname, "..", "client", "index.bundle.js")).pipe(inlinedJs);
    // Init express server
	var app = this.app = new express();

	// middleware for serving webpack bundle
	this.middleware = webpackDevMiddleware(compiler, options);

	app.get("/__webpack_dev_server__/live.bundle.js", function(req, res) {
		res.setHeader("Content-Type", "application/javascript");
		liveJs.pipe(res);
	});

	app.get("/webpack-dev-server.js", function(req, res) {
		res.setHeader("Content-Type", "application/javascript");
		inlinedJs.pipe(res);
	});

	app.get("/webpack-dev-server/*", function(req, res) {
		res.setHeader("Content-Type", "text/html");
		this.livePage.pipe(res);
	}.bind(this));

当使用Iframe mode时,请求/webpack-dev-server/index.html路径时,会返回client/index.html文件,这个文件的内容就是:

<!DOCTYPE html><html><head><meta http-equiv="X-UA-Compatible" content="IE=edge"/><meta charset="utf-8"/><meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/><script type="text/javascript" charset="utf-8" src="/__webpack_dev_server__/live.bundle.js"></script></head><body></body></html>

这个页面会请求live.bundle.js,其中里面会新建一个Iframe,你的应用就被注入到了这个Iframe当中。同时live.bundle.js中含有socket.ioclient代码,这样它就能和webpack-dev-server建立的http server进行websocket通讯了。并根据返回的信息完成相应的动作。

Inline-mode,是webpack-dev-server会在你的webpack.config.js的入口配置文件中再添加一个入口,

    module.exports = {
        entry: {
            app: [
                'webpack-dev-server/client?http://localhost:8080/',
                './src/js/index.js'
            ]
        },
        output: {
            path: './dist/js',
            filename: 'bundle.js'
        }
    }

这样就完成了将inlinedJS打包进bundle.js里的功能,同时inlinedJS里面也包含了socket.ioclient代码,可以和webpack-dev-server进行websocket通讯。

当然你也可以直接在你index.html引入这部分代码:

<script src="http://localhost:8080/webpack-dev-server.js"></script>

不过Iframe modeInline mode最后达到的效果都是一样的,都是监听文件的变化,然后再将编译后的文件推送到前端,完成页面的reload的。

###Iframe mode

Iframe modecmd line不需要添加其他的内容,浏览器访问的路径是:

localhost:8080/webpack-dev-server/index.html。

这个时候这个页面的header部分会出现整个reload消息的状态。当时改变源文件的时候,即可以完成自动编译打包,页面自动刷新的功能。

图片描述

###Inline mode

使用inline mode的时候,cmd line需要写成:

webpack-dev-server --inline --content-base ./dist

这个时候访问的路径是:

localhost:8080/index.html

也能完成自动编译打包,页面自动刷新的功能。但是没有的header部分的reload消息的显示,不过在控制台中会显示reload的状态。

图片描述

##Hot Module Replacement

开启Hot Module Replacement功能,在cmd line里面添加--hot

webpack-dev-server --hot --inline --content-base ./dist

##其他配置选项

--quiet 控制台中不输出打包的信息
--compress 开启gzip压缩
--progress 显示打包的进度

还有一切其他的配置信息可以查阅官方文档:

webpack-dev-server-cli

这是我的package.json的文件:

    {
  "name": "reptile",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack-dev-server --devtool eval-source-map --progress --colors --hot --inline --content-base ./dist",
    "build": "webpack --progress --colors"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.13.2",
    "babel-loader": "^6.2.5",
    "babel-preset-es2015": "^6.13.2",
    "babel-preset-react": "^6.11.1",
    "css-loader": "^0.23.1",
    "react": "^15.3.1",
    "react-dom": "^15.3.1",
    "style-loader": "^0.13.1",
    "webpack": "^1.13.2",
    "webpack-dev-server": "^1.14.1"
  }
}

首先命令行:输入 npm install 所有依赖。然后输入npm run dev。在浏览器中打开localhost:8080/index.html,然后就可以愉快的开发咯。

##本地搭建API Server
如果你在本地还启动了一个api server,port为3000,这个server主要和你的前端应用进行数据交互。这个时候很显然会出现跨域的问题,那么这个时候,你前端应用的入口文件应当是用你自己启动的api server提供的。

    var express = require('express');
    var app = express();
    
    app.get('/', function(req, res) {
        res.send('xxx/xxx/index.html'); //这个地方填写dist/index.html的路径
    })

此外webpack.config.js:

    module.exports = {
        entry: './src/js/index.js',
        output: {
            path: './dist/js',
            filename: 'bundle.js',
            publicPath: 'localhost:8080/dist'
        },
        devServer: {
            '/get': {
                targer: 'localhost:3000',
                secure: false
            }
        }
    }

publicPath字段的内容配置为绝对路径。同时index.html文件中对js引用的路径也改为绝对路径

    <script src="localhost:8080/dist/bundle.js"></script>

如果对web-dev-server还有其他问题的话,请留言告知。

另外2篇关于webpack的文章:

webpack1.x分包及异步加载套路
webpack2分包及异步加载套路

@javin9
Copy link

javin9 commented Jan 21, 2019

good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants