React 16.3.2集成Fly软件时遇window未定义错误求助
window is not defined错误 嘿,我来帮你拆解这个问题!首先得搞清楚为什么会出现这个错误:
错误原因
Fly的运行环境是Node.js/边缘计算服务端环境,这里没有浏览器特有的window、document这些全局对象。而你原来的代码(不管是直接运行ReactDOM.render还是把它放到fly.http.respondWith里),都是在Fly的服务端上下文执行的——这就相当于在服务器上试图调用浏览器才有的API,自然会报错。
React的ReactDOM.render是专门用来在客户端浏览器里渲染组件的,它依赖浏览器提供的DOM环境;而Fly的脚本是用来处理HTTP请求、返回响应的服务端逻辑,两者的运行环境完全不同。
解决方案:分两种场景处理
场景1:把React应用作为静态资源托管(适合新手,简单直接)
这种方式下,Fly只负责托管你的React静态文件(HTML、打包后的JS/CSS),React代码在用户的浏览器里运行,和普通的静态网站一样。
步骤1:调整Webpack配置
修改你的webpack.fly.config.js,确保输出路径和publicPath正确:
const path = require("path"); const webpack = require("webpack"); const bundlePath = path.resolve(__dirname, "dist/"); module.exports = { entry: "./src/index.js", module: { rules: [ { test: /\.(js|jsx)$/, exclude: /(node_modules|bower_components)/, loader: 'babel-loader', query: { presets: ['react']} }, { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] } ] }, resolve: { extensions: ['*', '.js', '.jsx'] }, output: { path: bundlePath, // 新增:指定打包文件输出到dist目录 publicPath: '/dist/', // 修改为绝对路径,方便HTML引用 filename: "bundle.js" }, // devServer是本地开发用的,Fly部署时不需要,可以注释掉 // devServer: { // contentBase: path.join(__dirname,'public'), // port: 3000, // publicPath: "http://localhost:3000/dist" // }, plugins: [ new webpack.HotModuleReplacementPlugin() ] };
步骤2:修正HTML的脚本引用
修改public/index.html里的script标签,用绝对路径引用打包后的JS:
<script src="/dist/bundle.js"></script>
步骤3:编写Fly的服务端脚本(新建一个fly.js作为入口)
这个脚本的作用是处理HTTP请求,返回对应的静态文件:
fly.http.respondWith(async (req) => { const url = new URL(req.url); // 根路径返回index.html if (url.pathname === "/") { try { const htmlContent = await fly.filesystem.read("public/index.html"); return new Response(htmlContent, { headers: { "Content-Type": "text/html; charset=utf-8" } }); } catch (err) { return new Response("无法加载首页", { status: 500 }); } } // dist目录下的静态资源(JS/CSS) if (url.pathname.startsWith("/dist/")) { const filePath = url.pathname.slice(1); // 去掉开头的/,变成dist/bundle.js try { const fileContent = await fly.filesystem.read(filePath); // 根据文件后缀设置Content-Type let contentType = "text/plain"; if (filePath.endsWith(".js")) contentType = "application/javascript"; if (filePath.endsWith(".css")) contentType = "text/css"; return new Response(fileContent, { headers: { "Content-Type": contentType } }); } catch (err) { return new Response("资源不存在", { status: 404 }); } } // 其他路径返回404 return new Response("页面不存在", { status: 404 }); });
步骤4:打包并部署
- 运行
webpack --config webpack.fly.config.js打包React代码到dist目录 - 确保你的Fly项目目录包含:
public/、dist/、fly.js、package.json - 用
fly deploy部署即可
场景2:服务端渲染(SSR,进阶用法)
如果想要在Fly的服务端渲染React组件,再把HTML返回给客户端,可以用ReactDOMServer的renderToString方法,同时客户端做hydrate(复用服务端渲染的DOM)。
示例Fly脚本(fly.js):
import React from 'react'; import ReactDOMServer from 'react-dom/server'; // 服务端渲染组件 const App = () => <h1>Hello, world!</h1>; fly.http.respondWith(async (req) => { // 生成组件的HTML字符串 const appHtml = ReactDOMServer.renderToString(<App />); // 拼接完整的HTML页面 const fullHtml = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>React SSR on Fly</title> </head> <body> <div id="root">${appHtml}</div> <script src="/dist/bundle.js"></script> </body> </html> `; return new Response(fullHtml, { headers: { "Content-Type": "text/html; charset=utf-8" } }); });
客户端React代码(src/index.js):
import React from 'react'; import ReactDOM from 'react-dom'; const App = () => <h1>Hello, world!</h1>; // 用hydrate替代render,复用服务端渲染的DOM ReactDOM.hydrate( <App />, document.getElementById('root') );
这种方式需要确保Fly环境安装了React和ReactDOM依赖,同时Webpack打包客户端代码的配置正确。
总结
作为React和Webpack新手,推荐先从**场景1(静态资源托管)**入手,这种方式更简单,符合你对React应用的常规认知。等你熟悉了React和Fly的运行机制后,再尝试SSR的进阶用法。
内容的提问来源于stack exchange,提问作者logos_164

