我正在尝试构建要部署到我的Heroku实例的生产版本。我使用的是最近使用过的样板,但是对于此项目,在部署页面后访问该页面时,我会在外部和公共资源上获取404。构建时不会抛出任何错误。
我知道由于找不到文件而抛出了MIME错误,但是经过过去4小时的故障排除后,我无法解决问题。
我尝试在href之前添加%PUBLIC_URL%
,但在构建时不会将其替换为位置。我还尝试过设置路径,以确保一切顺利(例如./
用于相对,而/
用于root)。
在构建时,我确实看到所有图像都包含在内,但其他文件都没有。
(附带说明:在Heroku上,我将NODE_ENV设置为“ production”,将在下面的服务器入口点中使用)
我转到该页面时在控制台中收到的错误列表如下:
GET https://mysite.herokuapp.com/js/lib/react.development.js 404 (Not Found)
-
mysite.herokuapp.com/:1 Refused to execute script from 'https://mysite.herokuapp.com/js/lib/react.development.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
-
mysite.herokuapp.com/:15 GET https://mysite.herokuapp.com/js/lib/react-dom.development.js 404 (Not Found)
-
mysite.herokuapp.com/:1 Refused to execute script from 'https://mysite.herokuapp.com/js/lib/react-dom.development.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
-
mysite.herokuapp.com/:1 Refused to apply style from 'https://mysite.herokuapp.com/css/lib/bootstrap.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
-
mysite.herokuapp.com/:18 GET https://mysite.herokuapp.com/js/lib/react-bootstrap.js 404 (Not Found)
-
mysite.herokuapp.com/:1 Refused to execute script from 'https://mysite.herokuapp.com/js/lib/react-bootstrap.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
-
mysite.herokuapp.com/:18 GET https://mysite.herokuapp.com/manifest.json 404 (Not Found)
-
manifest.json:1 Manifest: Line: 1, column: 1, Unexpected token.
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
mode: 'development',
entry: ["./src/index.tsx", "./src/index.css"],
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, '../../dist/client'),
},
devtool: 'eval-source-map',
resolve: {
extensions: [".ts", ".tsx", ".js"]
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
loader: "ts-loader",
exclude: /(node_modules|bower_components)/
},
{
test: /\.scss$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader'
},
{
loader: 'sass-loader?sourceMap',
options: {
includePaths: ['./src/**/*'],
sourceMap: true
}
}
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.jpe?g$|.gif$|.png$|.svg$|.woff$|.woff2$|.ttf$|.eot$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000
}
}
]
}
]
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.LoaderOptionsPlugin({
debug: true
}),
new HtmlWebpackPlugin({
template: './public/index.html',
inject: 'body',
filename: 'index.html'
}),
new webpack.ProvidePlugin({
React: 'React',
react: 'React',
'window.react': 'React',
'window.React': 'React',
}),
],
devServer: {
port: 8000,
contentBase: './public',
hot: true,
noInfo: false,
proxy: {
'/api/*': {
target: 'http://localhost:3000',
},
},
historyApiFallback: true
},
"externals": {
react: 'React',
jquery: 'jQuery',
'react-dom': 'ReactDOM',
'react-bootstrap': 'ReactBootstrap'
}
};
package.json
{
"name": "React-Node-App",
"version": "1.0.0",
"description": "",
"author": "",
"license": "ISC",
"homepage":".",
"scripts": {
"clean": "rimraf dist",
"dev:server": "concurrently \"tsc -w -p ./src/server\" \"nodemon --config ./src/server/nodemon.json dist/server/app.js\"",
"test:server": "mocha $NODE_DEBUG_OPTION --opts test/mocha.opts -r ts-node/register ./src/server/**/*.test.ts",
"lint": "ng lint",
"predev": "tsc -p ./src/server",
"dev": "concurrently \"npm run dev-client\" \"npm run dev:server\" ",
"dev:debug": "concurrently \"npm run dev-client\" \"tsc -w -p ./src/server\" \"nodemon --config ./src/srver/nodemon.json --inspect dist/server/app.js\"",
"start": "nodemon dist/server/app.js",
"postinstall": "tsc -p ./src/server",
"install": "npm run build-client",
"build:client": "cd ./src/client && webpack",
"build-client": "cd ./src/client && webpack -p",
"dev-client": "cd ./src/client && webpack-dev-server"
},
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "1.17.2",
"bootstrap": "^4.1.3",
"core-js": "2.4.1",
"cors": "^2.8.4",
"dotenv": "4.0.0",
"email-validator": "^2.0.3",
"eslint": "3.19.0",
"express": "4.15.3",
"font-awesome": "^4.7.0",
"handlebars": "^4.0.11",
"jquery": "^3.3.1",
"jwt-decode": "^2.2.0",
"jwt-simple": "^0.5.1",
"lodash": "^4.17.5",
"moment-timezone": "^0.5.16",
"mongoose": "^5.0.5",
"morgan": "^1.9.0",
"multer": "^1.3.0",
"node-sass-chokidar": "0.0.3",
"passport": "0.3.2",
"passport-anonymous": "^1.0.1",
"passport-jwt": "2.2.1",
"react": "^16.1.1",
"react-bootstrap": "^0.31.5",
"react-burger-menu": "^2.5.2",
"react-day-picker": "^7.1.10",
"react-dom": "^16.1.1",
"react-paginate": "^5.2.4",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-scripts": "1.0.17",
"react-slick": "^0.23.1",
"react-tabs": "^2.2.2",
"react-toastify": "^3.4.3",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0",
"reflect-metadata": "^0.1.12",
"routing-controllers": "^0.7.6",
"s3-streamlogger": "^1.3.1",
"slick-carousel": "^1.8.1",
"typedi": "^0.6.1",
"underscore": "^1.9.0",
"winston": "^2.4.2"
},
"devDependencies": {
"@types/chai": "^4.0.3",
"@types/mocha": "^2.2.41",
"@types/node": "^6.0.101",
"@types/react": "^16.3.10",
"awesome-typescript-loader": "^3.1.2",
"chai": "^4.1.1",
"concurrently": "3.5.0",
"cross-env": "^4.0.0",
"css-loader": "^0.28.11",
"eslint": "^4.1.1",
"eslint-plugin-react": "^7.1.0",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"jsdom": "^11.1.0",
"mocha": "^3.5.0",
"mocha-jsdom": "^1.1.0",
"mocha-junit-reporter": "^1.13.0",
"node-sass": "^4.9.0",
"nodemon": "1.12.7",
"nyc": "^11.5.0",
"protractor": "~5.1.2",
"rimraf": "^2.6.2",
"sass-loader": "^7.0.1",
"style-loader": "^0.21.0",
"ts-loader": "^4.2.0",
"ts-node": "^3.3.0",
"tslint": "~5.3.2",
"typescript": "~2.8.3",
"url-loader": "^1.0.1",
"webpack": "^4.6.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.1.2",
"webpack-dev-server": "^3.1.3"
},
"engines": {
"node": "6.11.2",
"npm": "5.5.1"
},
"nyc": {
"all": true,
"include": [
"src/**/*.js"
],
"cache": true
}
}
entry index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="manifest.json">
<link rel="shortcut icon" href="favicon.ico">
<script crossorigin src="/js/lib/react.development.js"></script>
<script crossorigin src="/js/lib/react-dom.development.js"></script>
<link rel="stylesheet" href="/css/lib/bootstrap.css">
<script src="/js/lib/react-bootstrap.js"></script>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
公共文件夹结构
服务器条目:
import * as dotenv from 'dotenv';
import * as morgan from 'morgan';
import * as passport from 'passport';
import * as bodyParser from 'body-parser';
import 'reflect-metadata'; // required
import './mixins/underscore';
import registerPassport from './config/passport';
import { createExpressServer, useContainer } from 'routing-controllers';
import { Container } from 'typedi';
import DatabaseSetup from './util/DatabaseSetup';
import UserController from './controllers/UserController';
import Logger from './util/Logger';
useContainer(Container);
const express = require('express');
const app = createExpressServer({
cors: true,
routePrefix: '/api',
controllers: [ UserController ]
});
if (process.env.NODE_ENV === 'production') {
app.use(express.static('dist/client'));
}
dotenv.load({ path: '.env' });
app.set('port', (process.env.PORT || 3000));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(morgan('dev'));
app.use(function (err, req, res, next) {
next(err);
});
Logger.setup();
new DatabaseSetup().setupDb(() => {
registerPassport(passport);
app.listen(app.get('port'), () => {
console.log('Listening on port ' + app.get('port'));
});
});
export { app };