在Docker应用中启用Webpack热重载

18

我有一个包含以下容器的Docker应用:

  1. node - 项目的源代码。它提供位于公共文件夹中的HTML页面。
  2. webpack - 监听节点容器中的文件,并在代码更改事件发生时(从节点容器)更新公共文件夹。
  3. 数据库

这是webpack/node容器的设置。

 web:
    container_name: web
    build: .
    env_file: .env
    volumes:
      - .:/usr/src/app
      - node_modules:/usr/src/app/node_modules
    command: npm start
    environment:
      - NODE_ENV=development
    ports:
      - "8000:8000"

  webpack:
    container_name: webpack
    build: ./webpack/
    depends_on:
      - web
    volumes_from:
      - web
    working_dir: /usr/src/app
    command: webpack --watch

目前,Webpack容器监控并更新公共文件夹。我必须手动刷新浏览器才能看到更改。

我现在正在尝试将webpack-dev-server集成到项目中,以便在浏览器中实现自动刷新。

这些是我对Webpack配置文件所做的更改。

module.exports = {
  entry:[
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:8080',
    './client/index.js'
  ],

  ....

  devServer:{
    hot: true,
    proxy: {
      '*': 'http://localhost:8000'
    }
  }
}

和新的docker-compose文件文件webpack

  webpack:
    container_name: webpack
    build: ./webpack/
    depends_on:
      - web
    volumes_from:
      - web
    working_dir: /usr/src/app
    command: webpack-dev-server --hot --inline
    ports:
      - "8080:8080"

当我运行这个应用程序时,似乎出现了一个错误。

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
webpack     |  - configuration.entry should be one of these:
webpack     |    object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function
webpack     |    The entry point(s) of the compilation.
webpack     |    Details:
webpack     |     * configuration.entry should be an object.
webpack     |     * configuration.entry should be a string.
webpack     |     * configuration.entry should NOT have duplicate items (items ## 1 and 2 are identical) ({
webpack     |         "keyword": "uniqueItems",
webpack     |         "dataPath": ".entry",
webpack     |         "schemaPath": "#/definitions/common.nonEmptyArrayOfUniqueStringValues/uniqueItems",
webpack     |         "params": {
webpack     |           "i": 2,
webpack     |           "j": 1
webpack     |         },
webpack     |         "message": "should NOT have duplicate items (items ## 1 and 2 are identical)",
webpack     |         "schema": true,
webpack     |         "parentSchema": {
webpack     |           "items": {
webpack     |             "minLength": 1,
webpack     |             "type": "string"
webpack     |           },
webpack     |           "minItems": 1,
webpack     |           "type": "array",
webpack     |           "uniqueItems": true
webpack     |         },
webpack     |         "data": [
webpack     |           "/usr/src/app/node_modules/webpack-dev-server/client/index.js?http://localhost:8080",
webpack     |           "webpack/hot/dev-server",
webpack     |           "webpack/hot/dev-server",
webpack     |           "webpack-dev-server/client?http://localhost:8080",
webpack     |           "./client/index.js"
webpack     |         ]
webpack     |       }).
webpack     |       [non-empty string]
webpack     |     * configuration.entry should be an instance of function
webpack     |       function returning an entry object or a promise..

正如您所看到的,我的条目对象没有任何重复的项。

我是否需要做一些额外的事情?我有没有遗漏什么?

webpack-dev-server基本上应该将所有请求代理到节点服务器。


为什么要添加这些条目:'webpack/hot/dev-server','webpack-dev-server/client?http://localhost:8080'? - Adam Wolski
@AdamWolski - 我相信这些路由是允许浏览器与Webpack服务器建立套接字连接以启用自动更新的关键。 - Jayaram
我认为你对“entry”字段及其含义存在一些误解。 - Adam Wolski
@AdamWolski - 我哪里做错了? - Jayaram
6个回答

12

如果正确配置,Docker和webpack-dev-server可以在没有任何中间件或插件的情况下完全运行:

devServer: {
  port: 80, // use any port suitable for your configuration
  host: '0.0.0.0', // to accept connections from outside container
  watchOptions: {
      aggregateTimeout: 500, // delay before reloading
      poll: 1000 // enable polling since fsevents are not supported in docker
  }
}

只有在您的 Docker 容器不支持 fsevents 时,请使用此配置。

如果要进行效率更高的检查,请查看HosseinAgha答案#42445288:在Docker应用程序中启用Webpack热重载


11

即使我将项目文件夹挂载到容器中,我仍无法让webpack或webpack-dev-server在(--watch)模式下工作。
要解决这个问题,您需要了解webpack如何检测目录中的文件更改情况。
它使用两个软件之一来添加操作系统级别支持以监视文件更改,称为inotifyfsevent。通常标准的Docker镜像没有预安装这些软件(尤其是针对Linux的inotify),因此您需要在Dockerfile中安装它们。
在发行版的软件包管理器中查找inotify-tools软件包并安装它。幸运的是,所有的alpinedebiancentos都有这个软件包。


3
这只涉及文件更改,这没有任何问题。webpack会立即重新编译。实际问题是浏览器的热重载。浏览器不会自动刷新...这就是所谓的热重载(参见问题标题)。 - sgohl
1
其他答案会启用不高效且随着文件系统树深度增加呈指数级变慢的webpack轮询。通过安装inotify,我们让watchpack监听更改事件而不是进行轮询。在那种情况下无需启用轮询。 - HosseinAgha
1
但问题不在于轮询。轮询和重新编译都正常工作。问题在于浏览器没有重新加载。浏览器中有一个 sockjs 服务,它调用了错误的 URL,可能是这个原因,但我不知道。 - sgohl

5

尝试执行以下操作:

  1. 在webpack配置中添加watchOptions.poll = true。

    watchOptions: { poll: true },

  2. 在devServer配置中配置主机

    host:"0.0.0.0",


我已经添加了配置,浏览器现在会自动更新了.. 但是更改没有反映 :( (甚至手动刷新后也是这样)- 你知道哪里可能出错吗?控制台显示webpack确实更新了静态文件。 - Jayaram
决定使用webpack-dev-middleware代替单独为webpack创建一个docker容器。 - Jayaram

4

热模块重载是最酷的开发模式之一,但在Docker上设置起来有点棘手。为了让它生效,您需要遵循以下8个步骤:

  1. 对于Webpack 5安装,特别是这些NPM包:
npm install webpack webpack-cli webpack-dev-server --save-dev --save-exact

将下面的命令写入“package.json”文件中的“scripts”部分:
```javascript "命令名称": "命令代码" ```
"dev": "webpack serve --mode development --host 0.0.0.0 --config webpack.config.js"
  1. 在 'webpack.config.js' 文件中添加此属性(它将启用 webpack 的模块热重载)
devServer: {
      port: 8080,
      hot: "only",
      static: {
        directory: path.join(__dirname, './'),
        serveIndex: true,
      },
    },

将以下代码添加到你的“index.js”(或其他)文件的底部,这是你的应用程序的入口点:
if (module.hot) {
  module.hot.accept()
}

在'docker-compose.yml'中暴露端口以便在http://localhost:8080看到应用程序。
ports:
      - 8080:8080
  • 使用docker-compose.yml中的卷将应用程序的/src目录与容器内的'src'目录同步。在我的情况下,目录'client'是所有前端React文件所在的地方,包括'package.json'、'webpack.config.js'和Dockerfile。而'docker-compose.yml'则放在上一级目录。
  • volumes:
          - ./client/src:/client/src
    
    1. 在卷组内,最好将同步“node_modules”目录的禁令加入其中(在此,“.dockerignore”无法起到帮助作用)。
    volumes:
          ...
          - /client/node_modules
    
    
  • 将整个打包过程从Docker的RUN命令中移除,而不是从您的'docker-compose.yml'文件的RUN命令中进行。
  • WORKDIR /client
    CMD ["npm", "run", "dev"]
    
    

    顺便提一下,如果您使用Webpack开发服务器,您在开发过程中就不需要其他Web服务器,如Nginx。还有一件重要的事情要记住,Webpack开发服务器不会将'/src'文件夹中的文件重新编译成'/disc'文件夹。它在内存中执行编译。


    4

    我曾在Windows设备上遇到过这个问题。通过在Docker Compose的环境中将WATCHPACK_POLLING设置为true,问题得以解决。

    frontend:
      environment:
        - WATCHPACK_POLLING=true
    

    -1

    我曾经遇到过同样的问题。但实际上这不是webpack或者docker的问题,而是我的问题。事实上,你需要检查Dockerfile中的工作目录是否与docker-compose.yml中绑定挂载的目标一致。

    Dockerfile

    FROM node
    ...
    workdir /myapp
    ...
    

    在你的docker-compose.yml文件中

    web:
       ....
       -volumes:
            ./:/myapp
    

    如果您在webpack.config.js上配置了重新加载,它应该可以正常工作。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接