本文介绍了React Flask Heroku App不显示前端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 问题摘要 我最近试图将我的本地应用程序部署到Heroku。它由Flask后端和React / Redux前端构建而成。通过Heroku的复杂工作(procfiles,它读取package.json等)后,我可以获得后端显示(例如:flask-admin部分和我的数据库一样工作) m仍然无法访问我网站的前端(反应)部分。在Heroku日志和本地版本中我没有发现任何错误,当我启动我的python服务器并在静态目录中执行 NPM start 时,我的应用程序完全正常工作。 任何想法为什么前端不会显示或如何访问它? 记录: 我已经从细节中删除了一些敏感信息,但这里是 heroku logs - tail 在我尝试刷新应用程序时给了我。 2018- 02-11T01:18:01.000000 + 00:00 app [api]:构建成功 2018-02-11T01:21:12.305017 + 00:00 heroku [web.1]:用命令`gunicorn main: app` 2018-02-11T01:21:16.374150 + 00:00 heroku [web.1]:状态从开始更改为 2018-02-11T01:21:15.948707 + 00:00应用[web.1]:[2018-02-11 01:21:15 +0000] [4] [INFO]启动gunicorn 19.6.0 2018-02-11T01:21:15.949430 + 00:00应用[ web.1]:[2018-02-11 01:21:15 +0000] [4] [INFO]听:ht tp://0.0.0.0:29162 2018-02-11T01:21:19.278810 + 00:00 heroku [router]:at = info method = GET path =/host = removed.herokuapp.com request_id = bd74ea4c-3e3a-403b-8850-198b7dec20e2 fwd =104.152.1.62dyno = web.1 connect = 1ms service = 2146ms status = 200 bytes = 2895 protocol = https 2018-02-11T01:21:19.650759 + 00:00 heroku [router]:at = info method = GET path =/ dist / bundle.csshost = removed.herokuapp.com request_id = 48183249-fb12- 4c7a-9a53-2a57ab58d89b fwd =104.152.1.62dyno = web.1 connect = 0ms service = 3ms status = 200 bytes = 2895 protocol = https 2018-02-11T01:21:19.816113 + 00:00 heroku [router]:at = info method = GET path =/ dist / bundle.jshost = removed.herokuapp.com request_id = 1c8b258b-4187-4df6-af35-784e62fb97e5 fwd =104.152.1.62dyno = web.1 connect = 1ms service = 3ms status = 200 bytes = 2895 protocol = https 我的index.html文件中的代码(在静态文件夹中,这是正确的),并且此特定行以红色突出显示哪个make我觉得它缺少bundle.js? < script src =/ dist / bundle.js>< / script> 最初的想法: 我的server.js文件实际上是从Heroku开始的吗?我在我的package.json中有一个start脚本,但是如果procfile正在执行Python ......它实际上是否启动?我如何在不将它安装到安装后或安装后步骤的情况下启动它? webpack搞乱了一些东西。我的产品webpack与我的开发有些不同,所以也许在构建过程中:生产会变得混乱起来?然而,这并不能解释为什么构建总是成功。 我的server.js或webpack在index.html文件上强制格式化,所以它可以没有正确解析?也许这就是为什么我看到 SyntaxError:expected expression,got'< bundle.js:1 在控制台? 更新: Heroku支持团队让我知道Heroku dynos不是为了支持像我这样的多进程应用程序而构建的。因此,他们觉得我需要做出一些重要的改变,让所有的HTTP请求都通过一个dyno进行转发。也许这是我的问题? 这些文件可能有助于调试: Server.js const http = require('http'); const express = require('express'); const httpProxy = require('http-proxy'); const path = require('path'); const apiPort = process.env.PORT || 8081; const proxy = httpProxy.createProxyServer({}); const app = express(); app.use(require('morgan')('short')); $ b $(函数initWebpack(){ const webpack = require('webpack'); const webpackConfig = require('./ webpack / common.config'); $ b $ const编译器= webpack(webpackConfig); app.use(require('webpack-dev-middleware'))(编译器,{ noInfo:true,publicPath: webpackConfig.output.publicPath,))); app.use(require('webpack-hot-middleware')(编译器,{ log:console.log, path:'/ __ webpack_hmr',心跳:10 * 1000,})); app.use(express.static(path.join(__ dirname,'/'))); }()); app.all(/ ^ \ / api\ /(.*)/,(req,res)=> { proxy.web(req, res,{target:`http://0.0.0.0:$ {apiPort}`}); }); app.get(/.*/,(req,res)=> { res.sendFile(path.join(__ dirname,'/index.html')); }); const server = http.createServer(app); server.listen(process.env.PORT || 8080,()=> { const address = server.address(); console.log('Listening on:%j ',address); console.log(' - >可能意味着:http://0.0.0.0:%d',address.port); }); 文件结构 ROOT ├──/ application │├──models.py │├──app.py ├─ ─/静态│├──/ bin │├──/ dist ││├──bundle.js│├──/ node_modules │ ├──/ src ││├──/ actions ││├──/ components │││├──/ examplecomponenthere ││││├── index.js(例如组件)││├──/常数││├──/ containers ││├──/ reducers ││├── / store ││├──/ webpack │├──index.html│├──package.json(真实的)│├──server。 js ├──/ tests ├──config.py├──index.py├──main.py├──package.json (一个帮助heroku开始)├──proc文件├──requirements.txt。 ├──setup.py├──tests.py Package.json in root 此文件存在是因为我正在运行多版本。 Heroku似乎无法识别package.json,直到我使用它将它推到那里。 {name:rmmd,version:0.0.1,engines:{node:6.11.1,npm:3.10.10},scripts:{start:node static / bin / server.js, heroku-postbuild:cd static& nmp install& npm run build:production} } Package.json in static { name:redux-easy-boilerplate,version:1.3.3,description:,scripts:{ clean:rimraf dist,build:webpack --progress --verbose --colors --display-error-details --config webpack / common.config.js ,build:production:npm run clean&& npm run build,lint:eslint src,start:node bin / server .js,test:业绩开始},回购type:git,url:},关键字:[react,reactjs,样板,redux,热,重新加载,hmr,live,edit,webpack],author:https://github.com/anorudes,https:// github .com / keske,license:MIT,devDependencies:{webpack-dev-middleware:^ 1.5.0, webpack-dev-server:^ 1.14.1,webpack-hot-middleware:^ 2.6.0,},dependencies:{ant-design-pro:^ 0.3.1,antd:^ 3.0.0,lodash:^ 4.17.4,prop-types:^ 15.6.0,react-bootstrap:^ 0.31.0,redux-devtools-extension:^ 2.13.2 ,autoprefixer:6.5.3,axios:^ 0.15.3,babel-core:^ 6.4.5,babel-eslint:^ 7.1.1,babel-loader:^ 6.2.1,babel-plugin-import:^ 1.2.1, babel-plugin-react-transform:^ 2.0.0,babel-plugin-transform-decorators-legacy:^ 1.3.4,babel-polyfill: ^ 6.3.14,babel-preset-es2015:^ 6.3.13,babel-preset-react:^ 6.3.13, babel-preset-react-hmre:^ 1.0.1,babel-preset-stage-0:^ 6.3.13,bootstrap:^ 3.3.5 ,bootstrap-loader:^ 1.2.0-beta.1,bootstrap-sass:^ 3.3.6,bootstrap-webpack: 0.0.5,classnames:^ 2.2.3,css-loader:^ 0.26.4,csswring:^ 5.1。 0,deep-equal:^ 1.0.1,eslint:^ 3.4.0,eslint-config-airbnb:13.0。 0,eslint-plugin-import:^ 2.2.0,eslint-plugin-jsx-a11y:^ 3.0.1,eslint- plugin-react:^ 6.1.2,expect:^ 1.13.4,exports-loader:^ 0.6.2,揭露-loader:^ 0.7.1,express:^ 4.13.4,express-in-editor:^ 1.1.0,额外ct-text-webpack-plugin:^ 1.0.1,file-loader:^ 0.9.0,gapi:0.0.3,history:^ 4.4.1,http-proxy:^ 1.12.0,imports-loader:^ 0.6.5, jasmine-core:^ 2.4.1,jquery:^ 3.1.0,jwt-decode:^ 2.1.0, karma:^ 1.2.0,karma-chrome-launcher:^ 2.0.0,karma-mocha:^ 1.1.1, karma-webpack:^ 1.7.0,less:^ 2.7.2,less-loader:^ 2.2.3, lodash:^ 4.5.1,material-ui:^ 0.16.4,mocha:^ 3.0.2,摩根: ^ 1.6.1,node-sass:^ 3.4.2,postcss-import:^ 9.0.0,postcss-loader :^ 1.1.1,q:^ 1.4.1,qs:^ 6.1.0,rc-datepicker:^ 4.0.1,react:^ 15.3.1,react-addons-css-transition-group:^ 15.3.1,react- bootstrap:^ 0.31.0,react-calendar-component:^ 1.0.0,react-date -picker:^ 5.3.28,react-datepicker:^ 0.37.0,react-document-meta:^ 2.0.0-rc2,react-dom:^ 15.1.0,react-forms:^ 2.0.0-beta33,react-hot-loader:^ 1.3 .0,react-loading-order-with-animation:^ 1.0.0,react-onclickoutside:^ 5.3.3,react -redux:^ 4.3.0,react-router:3.0.0,react-router-redux:^ 4.0.0, react-tap-event-plugin:^ 2.0.1,react-transform-hmr:^ 1.0.1,redux:^ 3.2.1 ,redux-form:^ 6.0.1,redux-logger:2.7.4,redux-thunk:^ 2.1.0 ,resolve-url-loader:^ 1.4.3,rimraf:^ 2.5.0,sass-loader:^ 4.0.0 ,style-loader:^ 0.13.0,url-loader:^ 0.5.7,webpack:^ 1.12.11 ,webpack-merge:^ 1.0.2,yargs:^ 6.5.0} } Webpack Prod const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); module.exports = { devtool:'source-map', 条目:['bootstrap-loader / extractStyles','./src/index '],输出:{ publicPath:'/ dist /',}, 模块:{加载器:[ { test:/\.scss$/, loader:'style!css!postcss-loader!sass',},],} , 插件:[新的webpack.DefinePlugin({$ b $'process.env':{ NODE_ENV:''production'',} , __DEVELOPMENT__:false,}),新的ExtractTextPlugin('bundle.css'),新的webpack.optimize.DedupePlugin(),新的webpack。优化.OccurenceOrderPlugin(),新的webpack.optimize.UglifyJsPlugin({压缩:{警告:false,},}), ],}; 常见的Webpack const path = require('path'); const autoprefixer = require('autoprefixer'); const postcssImport = require('postcss-import'); const merge = require('webpack-merge'); const development = require('./ dev.config'); const production = require('./ prod.config'); require('babel-polyfill')。default; const TARGET = process.env.npm_lifecycle_event; 常量PATHS = { app:path.join(__ dirname,'../src'), build:path.join(__ dirname,'../dist' ),}; process.env.BABEL_ENV = TARGET; $ b $常规= {条目:[ PATHS.app,], 输出:{路径: PATHS.build,文件名:'bundle.js',}, 解析:{扩展名:['','.jsx','。 js','.json','.scss'], modulesDirectories:['node_modules',PATHS.app],}, 模块:{加载器:[{ test:/ bootstrap-sass \ / assets \ / javascripts\ //, loader:'imports?jQuery = jquery',},{ test:/\.woff(\?v=\d+\.\d+\.\d+)?$/, loader:'url?limit = 10000& mimetype = application / font-woff',},{ test:/\.woff2(\?v=\d+\.\d+\.\d+)?$ /, loader:'url?limit = 10000& mimetype = application / font-woff2',},{ test:/\.ttf(\\ \\?v = \ d + \.\d + \.\d +)?$ /, loader:'url?limit = 10000& mimetype = application / octet-stream', },{ test:/\.otf(\?v=\d+\.\d+\.\d+)?$/, loader:'url?limit = 10000& mimetype = application / font-otf',},{ test:/\.eot(\?v=\d+\.\d+\.\ d +)?$ /, loader:'file',},{ test:/\.svg(\?v=\d+\.\d+\\ \\d +)?$ /, loader:'url?limit = 10000& mimetype = image / svg + xml',},{ test:/\.js $ /,加载器:['babel-loader'], exclude:/ node_modules /,},{ test:/\\.css$/, include:/ node_modules /,加载器:['style-loader','css-loader'],},{ test:/ \\.png $ /, loader:'file?name = [name]。[ext]',},{ test:/\.jpg$/, loader:'file?name = [name]。[ext]',}],}, postcss:(webpack)=> ( [ autoprefixer({ browsersers:['last 2 versions'],})] ),}; if(TARGET ==='start'||!TARGET){ module.exports = merge(development,common); if(TARGET ==='build'||!TARGET){ module.exports = merge(production,common); } ProcFile $ b web:gunicorn main:app $ b Heroku中的Buildpacks heroku buildpacks:set heroku / python heroku buildpacks:add heroku / nodejs 解决方案 事实证明,Heroku支持团队在分析我的申请时是不正确的。我的应用程序以两种不同的方式构建(一个用于生产和开发)。本地使用 npm run start [请参阅 static / package.json ]使用热重新加载,并通过server.js实现更快的本地更改。但是,在生产环境中,您希望使用压缩的bundle.js文件,因此我的目标是使用 npm run build:production [请参阅 static / package。 json ]。 我遇到的问题是 SyntaxError:expected expression,got'< bundle.js:1 在控制台中,在我看来,bundle.js根本没有加载。我列出了一系列关于为什么我认为可能会发生的有效问题,但他们都认为主要问题是无法与我的烧瓶应用程序同时运行我的反应应用程序。 我完全错了。我根本不需要运行server.js。 index.html和flask / python无法找到我的bundle.js并在生产中加载前端的真正原因是因为 config.py 中的错误,文件在烧瓶内,我从来没有想过发布。 Flask有一个非常特殊的配置,允许定义 static_folder 和 template_folder 。前段时间,我在处理某些图像上传功能时将我的static_folder换成了另一个目录。我从来没有发现它的原因是因为在本地我运行server.js热重新加载,所以我从来没有看到压缩bundle.js文件错误。 修复此错误后,我推到了heroku,令人惊讶......它在第一次尝试中就起作用了! 以下是修正它的正确代码: app = Flask (__name__,static_folder =./ static / dist,template_folder =./ static) 在结束时,在Heroku上运行烧瓶/反应应用程序: 使用多构建包(一个用于节点,一个用于python)。 > 使用procfile只加载烧瓶端。 您需要在根目录下有一个package.json文件,即使您在我的静态文件夹中有另一个。 使用webpack压缩你的反应代码并以压缩的方式提供它。 使用 render_template 来渲染index.html文件确保你所有的React依赖关系列在实际的依赖关系中,而不是devdepencies 否则Heroku会忽略它们。 我真的希望这有助于某人!我在头上撞了两个星期,结果是一个小问题......不是总是这样吗? 其他资源: https:// codeburst .io / creation-a-full-stack-web-application-with-python-npm-webpack-and-react-8925800503d9 虽然这是非常简单的...这是什么导致我找到我的bug,所以我'会在这里发布。 Summary of the issueI've recently tried to deploy my local application to Heroku. It's built with a Flask backend and a React/Redux frontend. After working through the intricacies of Heroku (procfiles, where it reads package.json, etc.) I'm able to get the backend to show (example: the flask-admin section is working as well as my database), but I'm still unable to reach the frontend (react) portion of my site. There are no errors that I can spot in the Heroku logs and on local version my application works perfectly fine when I start up my python server and do NPM start in the static directory.Any idea why the front end wouldn't be showing or how to access it?Logs:I've removed some sensitive information from the details, but here's what heroku logs --tail gives me when I try to refresh the app.2018-02-11T01:18:01.000000+00:00 app[api]: Build succeeded2018-02-11T01:21:12.305017+00:00 heroku[web.1]: Starting process with command `gunicorn main:app`2018-02-11T01:21:16.374150+00:00 heroku[web.1]: State changed from starting to up2018-02-11T01:21:15.948707+00:00 app[web.1]: [2018-02-11 01:21:15 +0000] [4] [INFO] Starting gunicorn 19.6.02018-02-11T01:21:15.949430+00:00 app[web.1]: [2018-02-11 01:21:15 +0000] [4] [INFO] Listening at: http://0.0.0.0:291622018-02-11T01:21:19.278810+00:00 heroku[router]: at=info method=GET path="/" host=removed.herokuapp.com request_id=bd74ea4c-3e3a-403b-8850-198b7dec20e2 fwd="104.152.1.62" dyno=web.1 connect=1ms service=2146ms status=200 bytes=2895 protocol=https2018-02-11T01:21:19.650759+00:00 heroku[router]: at=info method=GET path="/dist/bundle.css" host=removed.herokuapp.com request_id=48183249-fb12-4c7a-9a53-2a57ab58d89b fwd="104.152.1.62" dyno=web.1 connect=0ms service=3ms status=200 bytes=2895 protocol=https2018-02-11T01:21:19.816113+00:00 heroku[router]: at=info method=GET path="/dist/bundle.js" host=removed.herokuapp.com request_id=1c8b258b-4187-4df6-af35-784e62fb97e5 fwd="104.152.1.62" dyno=web.1 connect=1ms service=3ms status=200 bytes=2895 protocol=httpsWhen I view source I see the code from my index.html file (in the static folder, which is correct) and this particular line is highlighted red which makes me think it's missing bundle.js?<script src="/dist/bundle.js"></script>When I try to visit the front end, none of it is showing. I'm really unsure where to look next.Initial ideas:Is my server.js file actually starting on Heroku? I have a "start" script in my package.json, but if procfile is executing Python...does it actually start? How do I make it start without putting it into a postinstall or post-build step? Is webpack messing something up. My production webpack is slightly different from my development so maybe during build:production it's getting messed up? However, that doesn't explain why build is always succeeding.Is my server.js or webpack forcing formatting on the index.html file and so it can't parse properly? Perhaps this is why I'm seeing SyntaxError: expected expression, got '< bundle.js:1 in the console?Update: I received a note from the Heroku support team letting me know that Heroku dynos are not built to support multi processes applications like mine. As a result, they feel like I'd need to make some signficant changes to have all the HTTP requests forwarding through one dyno. Perhaps this is my issue?Here are files that may help debug:Server.jsconst http = require('http');const express = require('express');const httpProxy = require('http-proxy');const path = require('path');const apiPort = process.env.PORT || 8081;const proxy = httpProxy.createProxyServer({});const app = express();app.use(require('morgan')('short'));(function initWebpack() { const webpack = require('webpack'); const webpackConfig = require('./webpack/common.config'); const compiler = webpack(webpackConfig); app.use(require('webpack-dev-middleware')(compiler, { noInfo: true, publicPath: webpackConfig.output.publicPath, })); app.use(require('webpack-hot-middleware')(compiler, { log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000, })); app.use(express.static(path.join(__dirname, '/')));}()); app.all(/^\/api\/(.*)/, (req, res) => { proxy.web(req, res, { target: `http://0.0.0.0:${apiPort}` });});app.get(/.*/, (req, res) => { res.sendFile(path.join(__dirname, '/index.html'));});const server = http.createServer(app);server.listen(process.env.PORT || 8080, () => { const address = server.address(); console.log('Listening on: %j', address); console.log(' -> that probably means: http://0.0.0.0:%d', address.port);});File StructureROOT├──/application│ ├── models.py│ ├── app.py├──/static│ ├──/bin│ ├──/dist│ │ ├──bundle.js│ ├──/node_modules│ ├──/src│ │ ├──/actions│ │ ├──/components│ │ │ ├──/examplecomponenthere│ │ │ │ ├──index.js (for example component)│ │ ├──/constants│ │ ├──/containers│ │ ├──/reducers│ │ ├──/store│ │ ├──/webpack│ ├──index.html│ ├──package.json (the true one)│ ├──server.js├──/tests├──config.py├──index.py├──main.py├──package.json (one to help heroku start)├──procfile├──requirements.txt.├──setup.py├──tests.pyPackage.json in rootThis file exists because I'm running a multi build. Heroku doesn't seem to recognize the package.json in static until I use this one to push it over there. { "name": "rmmd", "version": "0.0.1", "engines": { "node": "6.11.1", "npm": "3.10.10" }, "scripts": { "start": "node static/bin/server.js", "heroku-postbuild": "cd static && npm install && npm run build:production" } }Package.json in static{ "name": "redux-easy-boilerplate", "version": "1.3.3", "description": "", "scripts": { "clean": "rimraf dist", "build": "webpack --progress --verbose --colors --display-error-details --config webpack/common.config.js", "build:production": "npm run clean && npm run build", "lint": "eslint src", "start": "node bin/server.js", "test": "karma start" }, "repository": { "type": "git", "url": "" }, "keywords": [ "react", "reactjs", "boilerplate", "redux", "hot", "reload", "hmr", "live", "edit", "webpack" ], "author": "https://github.com/anorudes, https://github.com/keske", "license": "MIT", "devDependencies": { "webpack-dev-middleware": "^1.5.0", "webpack-dev-server": "^1.14.1", "webpack-hot-middleware": "^2.6.0", }, "dependencies": { "ant-design-pro": "^0.3.1", "antd": "^3.0.0", "lodash": "^4.17.4", "prop-types": "^15.6.0", "react-bootstrap": "^0.31.0", "redux-devtools-extension": "^2.13.2","autoprefixer": "6.5.3", "axios": "^0.15.3", "babel-core": "^6.4.5", "babel-eslint": "^7.1.1", "babel-loader": "^6.2.1", "babel-plugin-import": "^1.2.1", "babel-plugin-react-transform": "^2.0.0", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-polyfill": "^6.3.14", "babel-preset-es2015": "^6.3.13", "babel-preset-react": "^6.3.13", "babel-preset-react-hmre": "^1.0.1", "babel-preset-stage-0": "^6.3.13", "bootstrap": "^3.3.5", "bootstrap-loader": "^1.2.0-beta.1", "bootstrap-sass": "^3.3.6", "bootstrap-webpack": "0.0.5", "classnames": "^2.2.3", "css-loader": "^0.26.4", "csswring": "^5.1.0", "deep-equal": "^1.0.1", "eslint": "^3.4.0", "eslint-config-airbnb": "13.0.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-jsx-a11y": "^3.0.1", "eslint-plugin-react": "^6.1.2", "expect": "^1.13.4", "exports-loader": "^0.6.2", "expose-loader": "^0.7.1", "express": "^4.13.4", "express-open-in-editor": "^1.1.0", "extract-text-webpack-plugin": "^1.0.1", "file-loader": "^0.9.0", "gapi": "0.0.3", "history": "^4.4.1", "http-proxy": "^1.12.0", "imports-loader": "^0.6.5", "jasmine-core": "^2.4.1", "jquery": "^3.1.0", "jwt-decode": "^2.1.0", "karma": "^1.2.0", "karma-chrome-launcher": "^2.0.0", "karma-mocha": "^1.1.1", "karma-webpack": "^1.7.0", "less": "^2.7.2", "less-loader": "^2.2.3", "lodash": "^4.5.1", "material-ui": "^0.16.4", "mocha": "^3.0.2", "morgan": "^1.6.1", "node-sass": "^3.4.2", "postcss-import": "^9.0.0", "postcss-loader": "^1.1.1", "q": "^1.4.1", "qs": "^6.1.0", "rc-datepicker": "^4.0.1", "react": "^15.3.1", "react-addons-css-transition-group": "^15.3.1", "react-bootstrap": "^0.31.0", "react-calendar-component": "^1.0.0", "react-date-picker": "^5.3.28", "react-datepicker": "^0.37.0", "react-document-meta": "^2.0.0-rc2", "react-dom": "^15.1.0", "react-forms": "^2.0.0-beta33", "react-hot-loader": "^1.3.0", "react-loading-order-with-animation": "^1.0.0", "react-onclickoutside": "^5.3.3", "react-redux": "^4.3.0", "react-router": "3.0.0", "react-router-redux": "^4.0.0", "react-tap-event-plugin": "^2.0.1", "react-transform-hmr": "^1.0.1", "redux": "^3.2.1", "redux-form": "^6.0.1", "redux-logger": "2.7.4", "redux-thunk": "^2.1.0", "resolve-url-loader": "^1.4.3", "rimraf": "^2.5.0", "sass-loader": "^4.0.0", "style-loader": "^0.13.0", "url-loader": "^0.5.7", "webpack": "^1.12.11", "webpack-merge": "^1.0.2", "yargs": "^6.5.0" }}Webpack Prodconst webpack = require('webpack');const ExtractTextPlugin = require('extract-text-webpack-plugin');module.exports = { devtool: 'source-map', entry: ['bootstrap-loader/extractStyles', './src/index'], output: { publicPath: '/dist/', }, module: { loaders: [ { test: /\.scss$/, loader: 'style!css!postcss-loader!sass', }, ], }, plugins: [ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"production"', }, __DEVELOPMENT__: false, }), new ExtractTextPlugin('bundle.css'), new webpack.optimize.DedupePlugin(), new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, }, }), ],};Webpack commonconst path = require('path');const autoprefixer = require('autoprefixer');const postcssImport = require('postcss-import');const merge = require('webpack-merge');const development = require('./dev.config');const production = require('./prod.config');require('babel-polyfill').default;const TARGET = process.env.npm_lifecycle_event;const PATHS = { app: path.join(__dirname, '../src'), build: path.join(__dirname, '../dist'),};process.env.BABEL_ENV = TARGET;const common = { entry: [ PATHS.app, ], output: { path: PATHS.build, filename: 'bundle.js', }, resolve: { extensions: ['', '.jsx', '.js', '.json', '.scss'], modulesDirectories: ['node_modules', PATHS.app], }, module: { loaders: [{ test: /bootstrap-sass\/assets\/javascripts\//, loader: 'imports?jQuery=jquery', }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff', }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-woff2', }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/octet-stream', }, { test: /\.otf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-otf', }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file', }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml', }, { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/, }, { test: /\.css$/, include: /node_modules/, loaders: ['style-loader', 'css-loader'], }, { test: /\.png$/, loader: 'file?name=[name].[ext]', }, { test: /\.jpg$/, loader: 'file?name=[name].[ext]', }], }, postcss: (webpack) => ( [ autoprefixer({ browsers: ['last 2 versions'], }) ] ),};if (TARGET === 'start' || !TARGET) { module.exports = merge(development, common);}if (TARGET === 'build' || !TARGET) { module.exports = merge(production, common);}ProcFileweb: gunicorn main:appBuildpacks in Herokuheroku buildpacks:set heroku/pythonheroku buildpacks:add heroku/nodejs 解决方案 So! It turns out Heroku support team was incorrect in their analysis of my application. My application is built in two different ways (one for production as well as for development). Using npm run start [see static/package.json] on local utilizes hot reloading and benefits from faster local changes via server.js. However, in a production environment, you want to use a compressed bundle.js file so my goal was to use npm run build:production [see static/package.json].The issue I was running into was SyntaxError: expected expression, got '< bundle.js:1 in the console and it seemed to me that bundle.js wasn't loading at all. I listed a series of valid questions above on why I thought that might happen, but they all assumed that the main problem was an inability to run my react application at the same time as my flask application.I was totally wrong. I didn't need to run server.js at all. The REAL reason that index.html and flask/python wasn't able to find my bundle.js and load the frontend on production was because of a mistake in the config.py file within flask which I never thought to post.Flask has a very particular configuration that allows static_folder to be defined and template_folder. A while back I had swapped my static_folder for another directory while working on some image upload functionality. The reason I never caught it is because on local I run server.js for hot reloading so I never saw the compressed bundle.js file error out.After fixing this mistake, I pushed to heroku and amazingly...it worked on the first try! Here's the correct code that fixed it: app = Flask(__name__, static_folder="./static/dist", template_folder="./static")In closing whilst running a flask/react application on Heroku:Use multi buildpacks (one for node, one for python).Use your procfile to load only the flask side. You need a package.json file in your root directory...even if you have another in your static folder like me.Use webpack to compress your react code and serve it up in a compressed way.Use render_template with flask to render the index.html file that holds you root div for react.make sure all your dependencies for React are listed inside of actual "dependencies" instead of "devdepencies" otherwise Heroku will ignore them.I really hope this helps someone! I was slamming my head against the wall for 2 weeks and it turned out to be a small obscure problem....isn't it always?Additional resources: https://codeburst.io/creating-a-full-stack-web-application-with-python-npm-webpack-and-react-8925800503d9 While this is very simplified...it's what lead me to finding my bug so I'll post it here. 这篇关于React Flask Heroku App不显示前端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-24 12:19