- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
问题总结
我最近尝试将我的本地应用程序部署到 Heroku。它是用 Flask 后端和 React/Redux 前端构建的。在处理了 Heroku 的复杂问题(procfiles,它读取 package.json 等)之后,我能够显示后端(例如:flask-admin 部分和我的数据库一样工作),但我'我仍然无法访问我网站的前端( react )部分。我在 Heroku 日志和本地版本上没有发现任何错误,当我启动我的 python 服务器并执行 NPM start
时,我的应用程序工作得很好。在静态目录中。
知道为什么前端不显示或如何访问它吗?
日志:
我已经从细节中删除了一些敏感信息,但这是 heroku logs --tail
当我尝试刷新应用程序时给我。
2018-02-11T01:18:01.000000+00:00 app[api]: Build succeeded
2018-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 up
2018-02-11T01:21:15.948707+00:00 app[web.1]: [2018-02-11 01:21:15 +0000] [4] [INFO] Starting gunicorn 19.6.0
2018-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: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.62" dyno=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.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=https
2018-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=https
当我查看源代码时,我看到了我的 index.html 文件中的代码(在 static 文件夹中,这是正确的)并且这一行以红色突出显示,这让我觉得它缺少 bundle.js? <script src="/dist/bundle.js"></script>
当我尝试访问前端时,没有显示任何内容。我真的不确定接下来要看哪里。
初步想法:
我的 server.js 文件实际上是在 Heroku 上启动的吗?我的 package.json 中有一个“开始”脚本,但是如果 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'));
(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);
});
文件结构
ROOT
├──/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.py
根目录中的 Package.json该文件存在是因为我正在运行多重构建。 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 && npm install && npm run build:production"
}
}
静态的 Package.json
{
"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 产品
const 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 通用
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;
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);
}
过程文件
web: gunicorn main:app
Heroku 中的 Buildpack
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 根本没有加载。我在上面列出了一系列关于为什么我认为这可能会发生的有效问题,但他们都认为主要问题是无法与我的 Flask 应用程序同时运行我的 React 应用程序。
我完全错了。我根本不需要运行 server.js。 index.html 和 flask/python 无法找到我的 bundle.js 并在生产环境中加载前端的真正原因是 config.py
中的一个错误。 flask 中的文件,我从未想过要发布。
Flask 有一个非常特殊的配置,允许 static_folder
待定义和template_folder
.前一段时间,我在处理一些图像上传功能时将我的 static_folder 换成了另一个目录。我从未发现它的原因是因为在本地我运行 server.js 进行热重载,所以我从未看到压缩的 bundle.js 文件出错。
修复这个错误后,我推送到 heroku,令人惊讶的是......它在第一次尝试时就成功了!
这是修复它的正确代码:
app = Flask(__name__, static_folder="./static/dist", template_folder="./static")
在 Heroku 上运行 flask/react 应用程序时关闭:
render_template
用 flask 渲染包含你的 index.html 文件 root
用于 react 的 div。我真的希望这对某人有帮助!我用头撞墙 2 周,结果发现这是一个不起眼的小问题......不是总是这样吗?
其他资源:https://codeburst.io/creating-a-full-stack-web-application-with-python-npm-webpack-and-react-8925800503d9虽然这非常简单……正是它让我找到了我的错误,所以我会把它贴在这里。
关于python - React Flask Heroku App 不显示前端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48713701/
1. HTML 结构 1.1 HTML 文件基本结构 第一个html程序 hello world! html 标签是整个 h
文件上传三种方案:1. form表单上传,2. iframe,3. FormData,base64上传文件,二进制流上传文件,二进制流下载文件。异步上传,大文件上传--切片:拆分上传请求断点续传显示上
1. HTML 结构 1.1 HTML 文件基本结构 第一个html程序 hello world! html 标签是整个 h
uniapp作为开发移动端的前端框架,目前国内是非常流行的,使用HbuilderX开发工具基于uniapp框架开发的系统可以方便的转换为小程序、APP等移动端程序,大大降低了移动开发的成本。网络
今天我们来复盘一下前端中css伪元素的知识以及如何用css伪元素来减轻javascript的压力,做出一些脑洞大开的图形。 预备知识 伪元素 伪元素是一个附加至选择器末的
今天给大家分享一些实用的JS代码片段,有需要的朋友欢迎收藏! 1、获取浏览器的版 functiongetBrowser(){ varUserAgent=navigator.us
1 . Wappalyzer 全球用户数:1,000,000+ Wappalyzer可以帮助我们了解目标网站的构建方式。工作当中存在大量此类情况,客户需要我们参照某些网站
在管理后台中我们会使用大量的表格表单组件, 导入导出各种报表, 有些场景还需要对报表数据进行可视化分析, 动态生成可视化图表, 笔者将基于以上场景, 总结一些实用的 Table 组件开发技巧,
3D动画效果现在越来越普及,已经被广泛的应用到了各个平台,比如阿里云,华为云,webpack官网等。它可以更接近于真实的展示我们的产品和介绍,带来极强的视觉冲击感。所以说,为了让自己更加优秀,c
QShop商城-快速开始-前端 工具准备 NodeJs 前端环境为NodeJs,下载地址:http://nodejs.cn/download/current/ 。 默认会用版
1. 初始JavaScript 1.1 什么是 JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行
1. WebAPI 背景知识 1.1 什么是 WebAPI JS 分成三个大的部分: ECMAScript: 基础语法部分 DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI
1. WebAPI 背景知识 1.1 什么是 WebAPI JS 分成三个大的部分: ECMAScript: 基础语法部分 DOM API: 操作页面结构 BOM API: 操作浏览器 WebAPI
1. 初始JavaScript 1.1 什么是 JavaScript JavaScript (简称 JS) 是世界上最流行的编程语言之一 是一个脚本语言, 通过解释器运行 主要在客户端(浏览器)上运行
有没有办法从页面访问 tomcat 服务器日志?如果有一些方法或实现可以做到这一点...... 最佳答案 PSI Probe可以列出您的 Tomcat 日志文件并显示它们的内容。您可以采用相同的方法,
我想知道是否有一些很好的免费网站性能分析工具,特别是前端。这主要是关于Javascript的。 现有工具(例如 Google Pagespeed)的问题在于它不适用于我的应用程序。在进入我的应用程序之
我曾经遇到一个 MySQL 前端应用程序,它在父行中显示外部链接行,例如,如果 Client 表有一个指向 Suburb 表的外键: (来源:vb123.com) 您知道可以执行此操作的任何前端吗?
我正在建立一个带有管理区域的网上商店来管理产品。在管理区域中,所有产品都是可见的,但在网上商店中,只有数据库表中标记为 active = 1 的产品是可见的。 我正在使用 Silex 并将存储库注册为
有可能在 C# 中制作 GUI,但在 C 或 C++ 中制作实际程序。 比如说我想制作一个聊天应用程序。我希望界面在 C# 中。但我想用 C 编写所有实际代码。这可能吗? 我找到了 http://ww
对于我自己的教育,我很好奇编译器使用哪个 C++ 前端和后端。您能告诉我以下技术在哪里使用以及它们有哪些标志/优势(如果有的话)? Open64 - 它是后端、前端还是两者兼而有之?哪些编译器使用它?
我是一名优秀的程序员,十分优秀!