I have a configurator that I am able to change size and color of a piece of furniture using Google's . I have it working great on localhost, but for some reason, when deploying my MERN project to Heroku, I keep getting CORS errors when I go to swap the materials? I am able to GET some of the textures no problem, but other's I'm getting the CORS error.
All materials/images come from the same S3 bucket, and has the correct CORS policy on AWS. And in my Server.js file I have app.useCors(());
middleware installed. Really confused as to why I can GET some items, but not all from the same S3 bucket.
The CORS error in example:
Access to image at 'https://scoutmaterials.s3.us-east-2.amazonaws.com/Lacquer/Lacquer_Nrm.jpg' from origin 'https://fathomless-brook-11892.herokuapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have it set up to where when a user "clicks" on a label it will then fire an event to "swap" the materials.
Here is the swatch layout (the images in value, data-value, data-value2 are the images I'm getting from the S3 bucket):
<div key={index} className='swatch-container'>
<input type="radio" name={`properties[${names[1]} Finish]`} id={`${names[1]} Finish[${item.name}]`} className='variant__input' value={item.name} defaultChecked={item === selectedInput} onChange={(event) => {setSelectedInput(event.target.value); document.querySelectorAll(`#${names[1]}`).forEach(label => label.classList.remove("selected")); event.target.parentNode.querySelector("label").classList.add("selected");}}></input>
<label
onClick={(e) => {
if(names[1] === 'Body'){
swapBody(e)
}
if(names[1] === 'Drawer'){
swapDrawers(e)
}
}}
className='material__button-label'
htmlFor={`${names[1]} Finish[${item.name}]`}
id={names[1]}
value={item.diffuse}
data-value={item.normal}
data-value2={item.orm}
style={{backgroundImage:`url(${item.thumbnail})`}}
crossorigin='use-credentials'
></label>
<div id='materialName'>{item.name}</div>
</div>
Here is the swapping code:
const swapBody = (event) => {
const modelViewer = document.querySelector('model-viewer#model-viewer')
const material = modelViewer.model.getMaterialByName('Body');
const diffuseSwap = async (channel) => {
const diffuse = await modelViewer.createTexture(event.target.getAttribute('value'));
if (channel.includes('base'))
{
material.pbrMetallicRoughness[channel].setTexture(diffuse);
}
}
const normalSwap = async (channel) => {
const normal = await modelViewer.createTexture(event.target.getAttribute('data-value'));
if (channel.includes('normal'))
{
material[channel].setTexture(normal);
}
}
const ORMSwap = async (channel) => {
const ORM = await modelViewer.createTexture(event.target.getAttribute('data-value2'));
if (channel.includes('metallic'))
{
material.pbrMetallicRoughness[channel].setTexture(ORM);
}
}
diffuseSwap('baseColorTexture');
normalSwap('normalTexture');
ORMSwap('metallicRoughnessTexture');
console.log("swapping material")
};
And finally my Server.js code, with the added cors() middleware:
require("dotenv").config();
const path = require('path');
const express = require("express");
const cors = require('cors');
const productRoutes = require("./server/routes/productRoutes");
const connectDB = require("./server/config/db");
const mongoose = require("mongoose");
const bodyParser = require('body-parser');
const Product = require('./server/models/Product')
connectDB();
const app = express();
const corsOptions = {
origin: "*",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
preflightContinue: false,
optionsSuccessStatus: 204
};
app.use(cors(corsOptions));
app.use(express.json());
app.use(bodyParser.json());
const AR = mongoose.model('AR', arSchema);
app.use("/api/products", productRoutes);
if(process.env.NODE_ENV === "production"){
app.use(express.static(path.join(__dirname, '/client/build')));
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'client', 'build', 'index.html'));
})
} else {
app.get('/', (req, res) => {
res.send('API running...');
});
}
// const PORT = process.env.PORT || 5000;
const PORT = process.env.PORT;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
@jub0bs lead me in the right direction. After digging around some more I found out that simply changing these values:
value={item.diffuse}
data-value={item.normal}
data-value2={item.orm}
To this:
value={`${item.diffuse}`}
data-value={`${item.normal}`}
data-value2={`${item.orm}`}
Not exactly sure what this does, but from my understanding it formats it to a string? Which would make since because it's supposed to be a URL, not a JS function.