React 应用程序在本地运行,但在推送到 heroku(prod)时失败并出现意外令牌“<”
React app runs locally but fails with unexpected token '<' when pushed to heroku (prod)
出于两个原因,我一直在重构我的 webpack 配置。首先,从中删除 extract-text-webpack-plugin
,因为它已被弃用,显然我应该使用 MiniCssExtractPlugin
而不是 css。其次,使用 splitChunks
为我的代码和 node_modules 中的所有内容创建一个单独的 js 和 css 文件似乎是个好主意。除了一个问题,它似乎工作得很好,当我 运行 一个 heroku 推送然后尝试加载我的应用程序时,浏览器在控制台中抛出一个 Uncaught SyntaxError: Unexpected token '<'
错误,我得到一个空白页面。
- 在开发服务器下运行没问题。
- 在 heroku local 下运行没问题。
- 我浏览了 heroku 的故障排除页面,但没有看到任何版本控制、gitignore、node_modules 等
- 我今天花了一半时间在谷歌上搜索这个错误,并阅读了其他堆栈溢出文章,但都无济于事。似乎基本问题与期望 js 的浏览器有关,但它正在变得 html。与没有正确转换有关?所以我在想我的 babel 配置和现在的多个文件可能出了什么问题,但承认我不知道我是否在正确的轨道上(例如
vendor.build.js
文件没有正确转换?)。
- 所以我怀疑问题与以某种方式拆分我的输出文件有关..
关于我看来唯一不同的是当我 运行 开发构建与生产构建时生成的文件,尽管我不确定这是否是问题的根源。显然我做错了什么,但我不知道是什么。
浏览器错误截图:
这是 vendors.bundle.js
中指向意外令牌错误的内容。这是我应用程序的 index.html
文件 btw:
在我上面的重构练习之后,基于下面的 webpack 配置,开发构建生成了 4 个文件:
产品构建生成更多文件:
我的 webpack.config.js
文件如下所示:
const path = require("path");
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
process.env.NODE_ENV = process.env.NODE_ENV || "development";
if (process.env.NODE_ENV === "test") {
require("dotenv").config({ path: ".env.test" });
} else if (process.env.NODE_ENV === "development") {
require("dotenv").config({ path: ".env.development" });
}
module.exports = (env) => {
const isProduction = env === "production";
return {
entry: ["babel-polyfill", "./src/app.js"],
output: {
path: path.join(__dirname, "public", "dist"),
filename: "bundle.js",
},
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all'
},
},
},
},
mode: isProduction ? 'production' : 'development',
module: {
rules: [
{
loader: "babel-loader",
test: /\.js$/,
exclude: /node_modules/,
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: !isProduction,
},
},
{
loader: "css-loader",
options: {
sourceMap: !isProduction,
},
},
{
loader: "less-loader",
options: {
sourceMap: !isProduction,
modifyVars: {
"primary-color": "#1c88bf",
"link-color": "#1c88bf",
"border-radius-base": "2px",
},
javascriptEnabled: true,
},
}
],
},
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: !isProduction,
},
},
{
loader: "css-loader",
options: {
sourceMap: !isProduction,
},
},
{
loader: "sass-loader",
options: {
sourceMap: !isProduction,
},
},
],
},
{
test: /\.(svg|eot|ttf|woff|woff2)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "fonts/",
},
},
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new MiniCssExtractPlugin({ filename: '[name].css'}),
new webpack.DefinePlugin({
"process.env.FIREBASE_API_KEY": JSON.stringify(process.env.FIREBASE_API_KEY),
"process.env.FIREBASE_AUTH_DOMAIN": JSON.stringify(process.env.FIREBASE_AUTH_DOMAIN),
"process.env.FIREBASE_DATABASE_URL": JSON.stringify(process.env.FIREBASE_DATABASE_URL),
"process.env.FIREBASE_PROJECT_ID": JSON.stringify(process.env.FIREBASE_PROJECT_ID),
"process.env.FIREBASE_STORAGE_BUCKET": JSON.stringify(process.env.FIREBASE_STORAGE_BUCKET),
"process.env.FIREBASE_MESSAGING_SENDER_ID": JSON.stringify(process.env.FIREBASE_MESSAGING_SENDER_ID),
}),
],
devtool: isProduction ? "source-map" : "inline-source-map",
devServer: {
contentBase: path.join(__dirname, "public"),
historyApiFallback: true,
publicPath: "/dist/",
},
};
};
我的 .babelrc
文件的价值..
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": "true"
}
]
]
}
您对 js 文件的调用似乎是 returning 您的 index.html,这就是浏览器抱怨 <
的原因。检查是否有一些路由配置错误,如果没有命中,将 return index.html,然后查找它不匹配的原因。
事实证明,在我的案例中,上面的文件名在开发版本和生产版本之间不同(见上面的屏幕截图)。因此,我的 index.html 指的是生产版本的错误文件名(参见上面的 index.html 脚本标签)。
我最终通过两个更改修复了它。首先,我修复了我的 webpack 配置,为 dev 和 prod 构建输出相同的文件名。对于如何做到这一点,这对我来说并不是很明显(我不确定为什么开发人员使用 vendors.bundle.js
而生产人员使用 1.bundle.js
),但它最终变得微不足道。在输出部分,我只需将文件名参数从 "bundle.js"
更改为 "[name].js"
.
新文件名:
webpack.config.js
变化:
output: {
path: path.join(__dirname, "public", "dist"),
filename: "[name].js",
},
然后,我构建了 dev 和 prod 版本以确认文件名现在相同。一旦我意识到它们是,我修改了我的 index.html
以使用之前的这两个文件名..
<script src="/dist/vendors.js"></script>
<script src="/dist/main.js"></script>
出于两个原因,我一直在重构我的 webpack 配置。首先,从中删除 extract-text-webpack-plugin
,因为它已被弃用,显然我应该使用 MiniCssExtractPlugin
而不是 css。其次,使用 splitChunks
为我的代码和 node_modules 中的所有内容创建一个单独的 js 和 css 文件似乎是个好主意。除了一个问题,它似乎工作得很好,当我 运行 一个 heroku 推送然后尝试加载我的应用程序时,浏览器在控制台中抛出一个 Uncaught SyntaxError: Unexpected token '<'
错误,我得到一个空白页面。
- 在开发服务器下运行没问题。
- 在 heroku local 下运行没问题。
- 我浏览了 heroku 的故障排除页面,但没有看到任何版本控制、gitignore、node_modules 等
- 我今天花了一半时间在谷歌上搜索这个错误,并阅读了其他堆栈溢出文章,但都无济于事。似乎基本问题与期望 js 的浏览器有关,但它正在变得 html。与没有正确转换有关?所以我在想我的 babel 配置和现在的多个文件可能出了什么问题,但承认我不知道我是否在正确的轨道上(例如
vendor.build.js
文件没有正确转换?)。 - 所以我怀疑问题与以某种方式拆分我的输出文件有关..
关于我看来唯一不同的是当我 运行 开发构建与生产构建时生成的文件,尽管我不确定这是否是问题的根源。显然我做错了什么,但我不知道是什么。
浏览器错误截图:
这是 vendors.bundle.js
中指向意外令牌错误的内容。这是我应用程序的 index.html
文件 btw:
在我上面的重构练习之后,基于下面的 webpack 配置,开发构建生成了 4 个文件:
产品构建生成更多文件:
我的 webpack.config.js
文件如下所示:
const path = require("path");
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
process.env.NODE_ENV = process.env.NODE_ENV || "development";
if (process.env.NODE_ENV === "test") {
require("dotenv").config({ path: ".env.test" });
} else if (process.env.NODE_ENV === "development") {
require("dotenv").config({ path: ".env.development" });
}
module.exports = (env) => {
const isProduction = env === "production";
return {
entry: ["babel-polyfill", "./src/app.js"],
output: {
path: path.join(__dirname, "public", "dist"),
filename: "bundle.js",
},
optimization: {
splitChunks: {
cacheGroups: {
default: false,
vendor: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
chunks: 'all'
},
},
},
},
mode: isProduction ? 'production' : 'development',
module: {
rules: [
{
loader: "babel-loader",
test: /\.js$/,
exclude: /node_modules/,
},
{
test: /\.less$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: !isProduction,
},
},
{
loader: "css-loader",
options: {
sourceMap: !isProduction,
},
},
{
loader: "less-loader",
options: {
sourceMap: !isProduction,
modifyVars: {
"primary-color": "#1c88bf",
"link-color": "#1c88bf",
"border-radius-base": "2px",
},
javascriptEnabled: true,
},
}
],
},
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
sourceMap: !isProduction,
},
},
{
loader: "css-loader",
options: {
sourceMap: !isProduction,
},
},
{
loader: "sass-loader",
options: {
sourceMap: !isProduction,
},
},
],
},
{
test: /\.(svg|eot|ttf|woff|woff2)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "fonts/",
},
},
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new MiniCssExtractPlugin({ filename: '[name].css'}),
new webpack.DefinePlugin({
"process.env.FIREBASE_API_KEY": JSON.stringify(process.env.FIREBASE_API_KEY),
"process.env.FIREBASE_AUTH_DOMAIN": JSON.stringify(process.env.FIREBASE_AUTH_DOMAIN),
"process.env.FIREBASE_DATABASE_URL": JSON.stringify(process.env.FIREBASE_DATABASE_URL),
"process.env.FIREBASE_PROJECT_ID": JSON.stringify(process.env.FIREBASE_PROJECT_ID),
"process.env.FIREBASE_STORAGE_BUCKET": JSON.stringify(process.env.FIREBASE_STORAGE_BUCKET),
"process.env.FIREBASE_MESSAGING_SENDER_ID": JSON.stringify(process.env.FIREBASE_MESSAGING_SENDER_ID),
}),
],
devtool: isProduction ? "source-map" : "inline-source-map",
devServer: {
contentBase: path.join(__dirname, "public"),
historyApiFallback: true,
publicPath: "/dist/",
},
};
};
我的 .babelrc
文件的价值..
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": "true"
}
]
]
}
您对 js 文件的调用似乎是 returning 您的 index.html,这就是浏览器抱怨 <
的原因。检查是否有一些路由配置错误,如果没有命中,将 return index.html,然后查找它不匹配的原因。
事实证明,在我的案例中,上面的文件名在开发版本和生产版本之间不同(见上面的屏幕截图)。因此,我的 index.html 指的是生产版本的错误文件名(参见上面的 index.html 脚本标签)。
我最终通过两个更改修复了它。首先,我修复了我的 webpack 配置,为 dev 和 prod 构建输出相同的文件名。对于如何做到这一点,这对我来说并不是很明显(我不确定为什么开发人员使用 vendors.bundle.js
而生产人员使用 1.bundle.js
),但它最终变得微不足道。在输出部分,我只需将文件名参数从 "bundle.js"
更改为 "[name].js"
.
新文件名:
webpack.config.js
变化:
output: {
path: path.join(__dirname, "public", "dist"),
filename: "[name].js",
},
然后,我构建了 dev 和 prod 版本以确认文件名现在相同。一旦我意识到它们是,我修改了我的 index.html
以使用之前的这两个文件名..
<script src="/dist/vendors.js"></script>
<script src="/dist/main.js"></script>