Express/Webpack 在 dokku 和 heroku 上失败

Posted

技术标签:

【中文标题】Express/Webpack 在 dokku 和 heroku 上失败【英文标题】:Express/Webpack failing on dokku and heroku 【发布时间】:2016-06-18 04:48:33 【问题描述】:

过程文件:

build: npm run prod
web: nodemon server.js

包.json

  "scripts": 
    "prod": "NODE_ENV=production webpack -p --config ./webpack.prod.config.js --progress --optimize-dupe"
  

Webpack.prod.config:

var path = require('path');
var webpack = require('webpack');

module.exports = 
  devtool: null,
  entry: [
    './assets/js/index'
  ],
  output: 
    path: path.join(__dirname, 'public/dist/'),
    filename: 'bundle.js',
    publicPath: '/public/'
  ,
  plugins: [
    new webpack.optimize.UglifyJsPlugin(
      minimize: true,
      compress: 
        warnings: false
      
    ),
    new webpack.DefinePlugin(
      'process.env':  NODE_ENV: '"production"' 
    )
  ],
  module: 
    loaders: [
      
        test: /\.js$/,
        loader: 'babel',
        include: path.join(__dirname, 'assets/js'),
        exclude: path.join(__dirname, 'node_modules/')
      ,
      
        test: /\.css$/,
        include: path.join(__dirname, 'assets/css'),
        loader: 'style-loader!css-loader'
      
    ]
  

Server.js:

var path = require('path'),
    express = require('express'),
    app = express(),
    port = process.env.PORT || 5000

app.use(express.static(path.join(__dirname, 'public')))

app.get('*', function(req, res) 
  res.sendFile(path.join(__dirname + '/index.html'))
)

var server = app.listen(port, function() 
    var host = server.address().address
    console.log('Listening at http://%s:%s', host, port)
)

错误:

Dokku,502 错误网关:

2016/03/03 22:43:12 [error] 5419#0: *303 connect() failed (111: Connection refused) while connecting to upstream, client: 185.49.14.190, server: xxx.xxx, request: "GET http://testp3.pospr.waw.pl/testproxy.php HTTP/1.1", upstream: "http://172.17.0.4:5000/testproxy.php", host: "testp3.pospr.waw.pl"
2016/03/03 23:54:58 [error] 5419#0: *305 connect() failed (111: Connection refused) while connecting to upstream, client: 185.49.14.190, server: xxx.xxx, request: "GET http://testp4.pospr.waw.pl/testproxy.php HTTP/1.1", upstream: "http://172.17.0.4:5000/testproxy.php", host: "testp4.pospr.waw.pl"
2016/03/04 00:55:35 [error] 5419#0: *307 connect() failed (111: Connection refused) while connecting to upstream, client: 207.46.13.22, server: xxx.xxx, request: "GET /robots.txt HTTP/1.1", upstream: "http://172.17.0.4:5000/robots.txt", host: "artempixel.com.br"
2016/03/04 00:55:41 [error] 5419#0: *309 connect() failed (111: Connection refused) while connecting to upstream, client: 207.46.13.22, server: xxx.xxx, request: "GET / HTTP/1.1", upstream: "http://172.17.0.4:5000/", host: "artempixel.com.br"

Heroku 的日志中没有错误,仅在前端:

Uncaught SyntaxError: Unexpected token < - bundle.js:1

npm run prod 应该在/public/dist/ 中创建一个文件,就像在我的本地机器上一样,但是这个目录在 heroku 实例或 dokku 实例上都不存在,没有错误显示它无法创建它,但是如果我尝试heroku run --app app mkdir public/dist,它会默默地失败,就好像我尝试访问它刚刚“创建”的目录一样,它不存在。我也试过手动运行npm run prod,成功了,没有创建目录,没有报错。

我相信我的快递服务器试图提供的服务也存在问题,我的bundle.js 被作为index.html 提供服务,我不确定这是否是没有bundle.js 服务的问题,或者,即使有,app.get('*') 已被错误配置并盲目地为index.html 提供服务。

我只是想要一个静态 index.html 文件来为我的 bundle.js 提供服务,这样 React 就可以接管并做它的事情,这对于 heroku 来说似乎是不可能的,所以我试图在两者之间插入一个快速服务器,任何想法?

【问题讨论】:

嗨,你是怎么解决这个问题的?我也有类似的问题:***.com/questions/44022938/… 【参考方案1】:

我在我的快速服务器中使用了一个与您正在使用的类似的块:

app.get('*', function(req, res) 
  res.sendFile(path.join(__dirname + '/index.html'))
)

在生产中,我的 bundle.js 文件存在于服务器上,但是这个块导致浏览器将 bundle.js 文件的内容解释为 index.html 文件的内容,这是存在 HTML 的地方以&lt; 开头的代码,因此出现错误。

对我来说,通过删除 app.get('*') 块在生产中解决了该错误。我认为我首先需要该块来锚定相对于根 url 的请求 url,而不是相对于当前页面的任何 url 路径。看来这对我来说不再是问题,也许是因为我在所有 ajax api 请求 url 前面都包含了前导“/”。

这个错误在生产环境中出现,但在开发环境中没有出现,可能是因为 webpack 开发服务器没有使用实际的包文件,而是将包保存在内存中。但是在生产中使用了一个实际的捆绑文件。

注意:为了让我的配置正常工作,我还必须确保 express 可以在适当的位置将包识别为静态文件:

app.use('/dist', express.static(path.join(__dirname, 'dist')));

'/dist', 部分是关键,否则包会显示在根路径中,而不是我的 webpack 配置输出指定的路径。

【讨论】:

我遇到了同样的问题,想使用您的解决方案,但我无法弄清楚您在此处描述的更改如何适应整个上下文。您能否分享有关您的服务器和应用程序文件结构的更多信息? '*' 使用 start 意味着对于节点的每个请求,响应都将是 html 页面。因此,如果您在 chrome 中打开网络选项卡并重新加载浏览器,您会看到对于 bundle.js,您会返回一个 HTML 文件,即 index.html。所以 app.get('/', function (req, res) res.sendFile(path.join(__dirname, "/client/dist/index.html")) );和 app.use(express.static(path.join(__dirname, "/client/dist")));将为节点和静态资源路由上的默认 GET 请求设置路径。所以它解决了问题【参考方案2】:

多个问题:

我没有在我的package.json 中使用postinstall,而是尝试通过Procfile 来实现这一点,现在我已经交换,dist 文件已正确创建。

在为bundle.js 服务的index.html 中,我正在寻找:/public/dist/bundle.js,其表示将转换为:/public/public/dist/bundle.js

像我一样设置一个新的 dokku 实例,通过调试设法搞砸了容器。

【讨论】:

以上是关于Express/Webpack 在 dokku 和 heroku 上失败的主要内容,如果未能解决你的问题,请参考以下文章

如何在 dokku node.js 应用程序中运行 docker 命令?

从 SSH 重新启动 Dokku 应用程序的正确命令是啥?

markdown 在数字海洋上运行Dokku的注意事项。

Dokku keycloak 重定向过多

Express + Webpack 弹性beantalk部署

React Routing with Express, Webpack dev middleware, React router dom