Reputation: 789
I've spent longer than I care to admit trying to figure this out and I was hoping someone could help out with this. I know there are some similar questions on SO but none of them worked for me, and none quite matched the issue I'm having.
I have a React frontend SPA with a Node Express server on the backend in a monorepo. This question only pertains to the deployment of the React SPA though. I've encountered this while trying to deploy to both Netlify and Vercel.
Here's the project structure of my repo:
myproject
- package.json
- packages
- api
- ...
- web
- dist
- index.html
- static // all minified by webpack
- js
- css
- media
- fonts
- x.hash.ttf
- y.hash.ttf
- ... .hash.ttf
- public
- index.html // source html file
- src
- index.css
- index.tsx
- assets
- roboto
- x.ttf
- y.ttf
- ... .ttf
- ...
When importing my Git repo into either Vercel or Netlify, I set my base directory as 'packages/dist/web' - the folder is then successfully detected.
However, during the build, I get an error message. I understand this is to do with resolving of the urls during the build, but I can't wrap my head around why this would be occuring during the build process in the cloud deployments.
I've tinkered with the webpack configuration quite a bit, trying to see if changing the output.publicPath property would make any difference, but values of "/", "./", "../", and "../../" for the outputs.publicPath property still result in the error, although they still allow my local build to be successful as well.
I'd really appreciate any help with getting this sorted out. Below is the error in Netlify, although the error stack trace is the same in Vercel.
10:59:41 AM: $ webpack --env mode=production
10:59:59 AM: assets by status 467 KiB [cached] 4 assets
10:59:59 AM: orphan modules 3.78 MiB [orphan] 72 modules
10:59:59 AM: runtime modules 917 bytes 5 modules
10:59:59 AM: cacheable modules 4.03 MiB
10:59:59 AM: modules by path ./node_modules/ 256 KiB 63 modules
10:59:59 AM: modules by path ./src/ 3.78 MiB
10:59:59 AM: ./src/index.tsx + 70 modules 3.78 MiB [built] [code generated]
10:59:59 AM: ./src/index.css 39 bytes [built] [code generated] [1 error]
10:59:59 AM: ERROR in ./src/index.css
10:59:59 AM: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
10:59:59 AM: ModuleBuildError: Module build failed (from ./node_modules/css-loader/dist/cjs.js):
10:59:59 AM: Error: Can't resolve 'assets/fonts/roboto/Roboto-Thinitalic.ttf' in '/opt/build/repo/packages/web/src'
at finishWithoutResolve (/opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:293:18)
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:362:15
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:410:5
10:59:59 AM: at eval (eval at create (/opt/build/repo/packages/web/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:410:5
10:59:59 AM: at eval (eval at create (/opt/build/repo/packages/web/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:25:1)
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/DescriptionFilePlugin.js:87:43
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:410:5
10:59:59 AM: at eval (eval at create (/opt/build/repo/packages/web/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:13:1)
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/enhanced-resolve/lib/Resolver.js:410:5
10:59:59 AM: at processResult (/opt/build/repo/packages/web/node_modules/webpack/lib/NormalModule.js:598:19)
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/webpack/lib/NormalModule.js:692:5
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/loader-runner/lib/LoaderRunner.js:399:11
10:59:59 AM: at /opt/build/repo/packages/web/node_modules/loader-runner/lib/LoaderRunner.js:251:18
10:59:59 AM: at context.callback (/opt/build/repo/packages/web/node_modules/loader-runner/lib/LoaderRunner.js:124:13)
10:59:59 AM: at Object.loader (/opt/build/repo/packages/web/node_modules/css-loader/dist/index.js:155:5)
10:59:59 AM: at processTicksAndRejections (internal/process/task_queues.js:97:5)
10:59:59 AM: @ ./src/index.tsx 4:0-21
10:59:59 AM: 1 ERROR in child compilations
10:59:59 AM: webpack 5.21.1 compiled with 2 errors in 16507 ms
10:59:59 AM:
10:59:59 AM: ────────────────────────────────────────────────────────────────
10:59:59 AM: "build.command" failed
10:59:59 AM: ────────────────────────────────────────────────────────────────
10:59:59 AM:
10:59:59 AM: Error message
10:59:59 AM: Command failed with exit code 1: webpack --env mode=production
10:59:59 AM:
10:59:59 AM: Error location
10:59:59 AM: In Build command from Netlify app:
10:59:59 AM: webpack --env mode=production
10:59:59 AM:
10:59:59 AM: Resolved config
10:59:59 AM: build:
10:59:59 AM: base: /opt/build/repo/packages/web
10:59:59 AM: command: webpack --env mode=production
10:59:59 AM: commandOrigin: ui
10:59:59 AM: publish: /opt/build/repo/packages/web/dist
Here's my webpack config file as well:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = function (env) {
const isEnvProduction = env.mode === 'production'
const isEnvDevelopment = env.mode === 'development'
const cssLoaders = []
isEnvDevelopment && cssLoaders.push(require.resolve('style-loader'))
isEnvProduction && cssLoaders.push({
loader: MiniCssExtractPlugin.loader,
options: { publicPath: '../../' }
})
cssLoaders.push({
loader: require.resolve('css-loader'),
options: { sourceMap: true, importLoaders: 2, url: true }
})
return {
mode:
isEnvProduction ? 'production' :
isEnvDevelopment ? 'development'
: 'none',
entry: './src/index.tsx',
devServer: {
open: true,
port: 8888,
contentBase: path.join(__dirname, '/public'),
historyApiFallback: {
disableDotRule: true,
index: '/'
},
},
output: {
path: path.join(__dirname, '/dist'),
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
sourceMapFilename: "[name].js.map",
publicPath: '../../'
},
module: {
rules: [
{
use: cssLoaders,
test: /\.css$/i,
include: /src/
},
{
loader: 'babel-loader',
test: /\.(js|jsx|tsx|ts)$/i,
exclude: /node_modules/
},
{
use: require.resolve('source-map-loader'),
test: /\.js$/,
enforce: 'pre'
},
{
loader: require.resolve('file-loader'),
test: /\.(jpg|jpeg|svg|png)$/,
options: {
name: 'static/media/[name].[hash:8].[ext]'
}
},
// I've also tried using this method of resolving fonts with no difference
// {
// type: 'asset/resource',
// test: /\.(woff|woff2|eot|ttf|otf)$/,
// generator: {
// filename: 'static/fonts/[name][hash:8].[ext]'
// }
// },
{
loader: require.resolve('file-loader'),
test: /\.(woff|woff2|eot|ttf|otf)$/,
options: {
name: 'static/fonts/[name][hash:8].[ext]'
}
},
]
},
resolve: {
extensions: ['*', '.js', '.jsx', '.tsx', '.ts']
},
plugins: [
new HtmlWebpackPlugin({
title: 'DojoLaunch',
template: './public/index.html',
inject: true,
... isEnvProduction && {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
}),
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
})
],
performance: false
}
}
Thank you for your time!
Upvotes: 0
Views: 442
Reputation: 15106
This could be an issue with capitalization that only manifests on case-sensitive file systems. From the build output it looks like you're referring to Roboto-Thinitalic.ttf
in your sources, but the common filename for the font is Roboto-ThinItalic.ttf
with a capitalized I
.
Upvotes: 1