深入浅出webpack -- webpack-dev-server 常用配置及原理

一、初始化项目

《深入浅出webpack-热更新》

二、devServer常用的配置

1、host: '0.0.0.0'

devServer.host配置项用于配置DevServer服务监听的地址,只能通 过命令行参数传入。host的默认值是 127.0.0.1,即只有本地可以访问DevServer的HTTP服务。若想让局域网中的其他设备访问自己的本地 服务,则可以在启动DevServer时带上--host 0.0.0.0。

2、open

devServer.open用于在DevServer启动且第一次构建完时,自动用我 们的系统的默认浏览器去打开要开发的网页。还提供了 devServer.openPage 配置项来打开指定 URL的网页。

3、inline

默认为true。它用来控制是否向 Chunk中注入代理客户端,默认会注入。事实上,在开启inline时, DevServer会向每个输出的Chunk中注入代理客户端的代码,当我们的项 目需要输出很多Chunk时,就会导致构建缓慢。其实要完成自动刷新, 一个页面只需要一个代理客户端,DevServer之所以粗暴地为每个Chunk都注入,是因为它不知道某个网页依赖哪几个 Chunk,索性全部都注入 一个代理客户端。网页只要依赖了其中任何一个Chunk,代理客户端就 被注入网页中。这里的优化思路是关闭还不够优雅的inline模式,只注入一个代理 客户端。

设置为false,需要访问网址:http://localhost:8080/webpack-dev-server/

要开发的网页被放进了一个iframe中,编辑源码后,iframe会被自 动刷新。要输出的Chunk数量越多,构建性能提升的效果越明显。

4、historyApiFallback

路由重定向,找不到路径的情况下,不会出现找不到页面的情况,会停留在当前页面。

没有配置前访问一个不存在的页面:

当使用 HTML5 History API 时,任意的 404 响应都可能需要被替代为 index.html。通过传入以下启用:

historyApiFallback: true

配置后访问一个不存在的页面,会依然停留在当前页面:

配置也支持传递一个对象:

historyApiFallback: {
  rewrites: [
    { from: /^\/$/, to: '/views/landing.html' },
    { from: /^\/subpage/, to: '/views/subpage.html' },
    { from: /./, to: '/views/404.html' }
  ]
}

to也可以是一个函数:

historyApiFallback: {
      rewites: [
        {
          from: /^\/([-~]+)/,
          to: function(context) {
            return './'+context.match[1]+'html'
          }
        }
      ]
    },

5、lazy 

优化打包速度,多入口情况下需要开启,只有被访问的入口文会进行编译,不开启的话会把所有入口都编译。

6、overlay

把错误显示在页面上,遮罩显示。

7、hot

hot:true, 修改css文件页面不刷新,只更新。修改js文件会发生reload更新,也就是页面刷新。

8、hotOnly

设置为true,禁用掉所有的页面刷新,只使用模块热更新。

9、port

指定要监听请求的端口号,默认8080

port: 8081
webpack-dev-server --port 8081

 10、proxy

proxy: {
  "/api": "http://localhost:3000"
}

请求到 /api/users 现在会被代理到请求 http://localhost:3000/api/users

如果你不想始终传递 /api ,则需要重写路径:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    pathRewrite: {"^/api" : ""}
  }
}

请求到 /api/users 现在会被代理到请求 http://localhost:3000/users。 

对于浏览器请求,你想要提供一个 HTML 页面,但是对于 API 请求则保持代理。你可以这样做:

proxy: {
  "/api": {
    target: "http://localhost:3000",
    bypass: function(req, res, proxyOptions) {
      if (req.headers.accept.indexOf("html") !== -1) {
        console.log("Skipping proxy for browser request.");
        return "/index.html";
      }
    }
  }
}

支持匹配多个

proxy: {
      '/': { // 匹配所有的请求
        target:'https://mooc.study.163.com', // /smartSpec/detail/1202816603.html 
        changeOrigin: true,
        
      },
      '/smartSpec': { // 匹配 /smartSpec开头的
        target:'https://mooc.study.163.com', // /smartSpec/detail/1202816603.html
        changeOrigin: true,
        pathRewrite: {
          '^/smartSpec/qd':"smartSpec/detail/1202816603.html" //  请求这个/smartSpec/qd 就代表请求 /smartSpec/detail/1202816603.html
        }
      },
    }

三、webpack-dev-server的原理

  • 当运行 webpack-dev-server的时候会执行webpack-dev-server.js文件,这个是webpack-dev-server/bin中的文件。它调用webpack的api,传递config,生成compiler,compiler = webpack(config);再传递给server = new Server(compiler, options, log);Server在 webpack-dev-server/lib中的Server.js中定义,这个文件主要负责开启本地服务,设置静态文件路径;但是在执行webpack后,并没有看到有打包后的文件输出。打开浏览器是怎么访问到需要的资源的呢?是因为webpack-dev-middleware
  • webpack-dev-middleware中开启了webpack的监听模式:监听资源的变更,然后自动打包。资源文件变化会重新打包,然后把文件放置在内存当中不输出文件,输入输入内存比较快。
    context.watching = compiler.watch(options.watchOptions, (err) => {
      if (err) {
        context.log.error(err.stack || err);
        if (err.details) {
          context.log.error(err.details);
        }
      }
    });

webpack-dev-middleware的主入口文件,返回的是一个中间件:

module.exports = function wdm(compiler, opts) {
  const options = Object.assign({}, defaults, opts);

  // defining custom MIME type
  if (options.mimeTypes) {
    const typeMap = options.mimeTypes.typeMap || options.mimeTypes;
    const force = !!options.mimeTypes.force;
    mime.define(typeMap, force);
  }

  const context = createContext(compiler, options);

  // start watching
  if (!options.lazy) {
    context.watching = compiler.watch(options.watchOptions, (err) => {
      if (err) {
        context.log.error(err.stack || err);
        if (err.details) {
          context.log.error(err.details);
        }
      }
    });
  } else {
    if (typeof options.filename === 'string') {
      const filename = options.filename
        .replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&') // eslint-disable-line no-useless-escape
        .replace(/\\\[[a-z]+\\\]/gi, '.+');

      options.filename = new RegExp(`^[/]{0,1}${filename}$`);
    }

    context.state = true;
  }

  if (options.writeToDisk) {
    toDisk(context);
  }

  setFs(context, compiler);

  return Object.assign(middleware(context), {
    close(callback) {
      // eslint-disable-next-line no-param-reassign
      callback = callback || noop;

      if (context.watching) {
        context.watching.close(callback);
      } else {
        callback();
      }
    },

    context,

    fileSystem: context.fs,

    getFilenameFromUrl: getFilenameFromUrl.bind(
      this,
      context.options.publicPath,
      context.compiler
    ),

    invalidate(callback) {
      // eslint-disable-next-line no-param-reassign
      callback = callback || noop;

      if (context.watching) {
        ready(context, callback, {});
        context.watching.invalidate();
      } else {
        callback();
      }
    },

    waitUntilValid(callback) {
      // eslint-disable-next-line no-param-reassign
      callback = callback || noop;

      ready(context, callback, {});
    },
  });
};

简化一下webpack-dev-server如下: 

const express = require('express')
const webpackDevMid = require('webpack-dev-middleware');
const webpackHotMid = require('webpack-hot-middleware')
const webpack = require('webpack');
const app = express()
const config = require('./webpack.common')
Object.keys(config.entry).forEach(function(name) {
    config.entry[name] = ['webpack-hot-middleware/client?noinfo=true&reload=true'].concat(config.entry[name])
})
const compiler = webpack(config)
app.use(webpackDevMid(compiler, {}))
app.use(webpackHotMid(compiler, {
    overlayStyles: true
}))
 
app.listen(2000)

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值