Live Reloading 和 Hot Reloading 的区别
Live Reloading是在浏览器进行更改后自动重新加载整个页面,使开发者不再需要切换浏览器手动点击 cmd + r
。在这点上 Phoenix 通过 Phoenix LiveReload 可以提供开箱即用的支持,通过 mix phx.new
创建的项目默认配置了 Phoenix LiveReload。
但是,Live Reloading依然存在一个缺点,在开发现在越来越高度交互的 Web 应用时,频繁的代码改动与调试,意味着频繁的重新加载整个页面,很多情况你也许只希望修改一些样式,Live Reloading会显得尤为耗时,而为了解决这个问题,Hot Reloading 显得尤为重要。
注意事项
本文通过 React + Webpack 进行配置举例(因为自身业务),以前 React 的 Hot Reloading 是通过 HMR
(Hot Module Replacement) 实现的,因为一些技术原因不再使用这种方法。
我们将使用 @pmmmwh/react-refresh-webpack-plugin 这个实验性的 Webpack 插件来实现,虽然这个插件在运行一段时间后,webpack-dev-server
最终会吃掉大量内存,但是依然可以通过合适的配置和手动刷新,使其成为一个强大的工具。
NPM
首先在你的前端项目中执行,如果你是用的是 yarn
请自行修改命令
npm install --save-dev @pmmmwh/
react-refresh-webpack-plugin
webpack-dev-server react-refresh
react-refresh-typescript
Webpack 配置
在逻辑结构上我们将把 webpack-dev-server
置于 Phoenix 应用之前。使 Webpack 能够将 websocket 注入页面,以便在需要进行 Hot Reloading 时通知浏览器。为了更好地理解,我们配置 webpack-dev-server
启动在 4000 端口并且代理所有的请求到 4001 端口,也就是我们 Phoenix 应用运行的端口。所以现在浏览器仍然像 http://localhost:4000
发出请求,但是将会被透明代理到 Phoenix。
以下是 Webpack 的配置实例
assets/webpack.config.js
1const ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
2const ReactRefreshTypeScript = require("react-refresh-typescript");
3const PHOENIX_TARGET = "http://localhost:4001";
4
5module.exports = (env, options) => {
6
7const isDevelopment = options.mode !== "production";
8
9return {
10 mode: options.mode,
11 // We use `webpack serve` for hot reloading with phoenix
12 // Phoenix serves to 4001, and webpack serves to 4000
13 // Developers should use 4000 for hot reload
14 devServer: {
15 proxy: {
16 // All requests that webpack doesn't handle
17 // go through to the Phoenix server
18 "*": {
19 target: PHOENIX_TARGET,
20 secure: false,
21 // We don't specify ws: true here because
22 // webpack serve --hot requires
23 // its own non-phoenix websocket
24 // (ws://localhost:4000/ws) for reloading modules
25 },
26 // WS: Live reload the entire website for development
27 "/phoenix/live_reload/socket/websocket": {
28 target: PHOENIX_TARGET,
29 secure: false,
30 ws: true,
31 },
32 // WS: Live view
33 "/live/websocket": {
34 target: PHOENIX_TARGET,
35 secure: false,
36 ws: true,
37 },
38 // WS: For our data and presence
39 "/socket/websocket": {
40 target: PHOENIX_TARGET,
41 secure: false,
42 ws: true,
43 },
44 },
45 devMiddleware: {
46 // webpack serve copies files into memory
47 // but we need it on disk to serve from
48 // proxied Phoenix's :4001 server
49 writeToDisk: true,
50 },
51 },
52 ... rest of webpack config
53 };
54};
如上所示,列出了三种不同的 websocket,第一个用于 Phoenix LiveReload,第二个用于 Phoenix LiveView,第三个用于 Phoenix Channels。你也许已经自定义了这些配置的具体说明,可以在 MyAppWeb.Endpoint
中查找关键字 socket/3
。
在 loader
中找到 ts-loader
(假设你已经在用 Typescript )并添加 getCustomTransformers
和 transpileOnly
(注意 isDevelopment
变量在前面的代码中已经声明):
1{
2 loader: "ts-loader",
3 options: {
4 getCustomTransformers: () => ({
5 before: [isDevelopment && ReactRefreshTypeScript()].filter(Boolean),
6 }),
7 transpileOnly: isDevelopment,
8 ... other ts-loader options
9 },
10},
然后你需要在 plugins 中添加 ReactRefreshPlugin
:
1plugins: [
2 isDevelopment && new ReactRefreshPlugin(),
3 ... other plugins
4].filter(Boolean)
硬盘写入
Webpack 通过 webpack-dev-server 构建的所有内容,只会保存在内存中,如此一来 Phoenix 无法渲染我们的静态文件。
在默认的 Phoenix 配置中中,我们使用 Webpack [CopyPlugin
](https://webpack.js.org/plugins/copy-webpack-plugin/#root)将静态文件从 assets/static
复制到 priv/static
。
但是使用 webpack-dev-server 的情况下,所有内容都是从内存中提供的(并且它不提供静态文件),所以我们需要启用 writeToDisk
选项来实际写出静态文件,以便 Phoenix 可以为它们提供服务。这就是为什么我们必须在 webpack-dev-server Webpack 配置片段中添加 writeToDisk: true
。
Phoenix 配置实例
1config :my_app, MyAppWeb.Endpoint,
2http: [port: 4001],
3url: [port: 4000],
4# also change your watchers
5# configuration to run webpack serve:
6watchers: [
7 node: [
8 "node_modules/webpack/bin/webpack.js",
9 # this indicates to webpack
10 # to run the webpack-dev-server
11 "serve",
12 "--watch-options-stdin",
13 "--port",
14 # webpack serves to 4000 to enable hot reloading,
15 # but proxies to 4001 for phoenix
16 # to handle the request
17 "4000",
18 "--mode",
19 "development",
20 cd: Path.expand("../assets", __DIR__)
21 ]
22],
23... other configuration
在 dev.exs
中,将 http 端口更改为 4001,然后将 url 设置为 4000。这将使 Phoenix 绑定到端口 4001,它将实际侦听请求,但生成到端口 4000 的链接,如此一来 webpack-dev-server 便能正常工作。