Cant load Font || caught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON at JSON.parse (<anonymous>)

// My CODE =======================================================

import * as THREE from “three”;
import { OrbitControls } from “three/examples/jsm/controls/OrbitControls”;
import { FontLoader } from “three/examples/jsm/loaders/FontLoader”
import { TextGeometry } from “three/examples/jsm/geometries/TextGeometry”
import * as debugUI from “lil-gui”;

// RENDRERE -----------------------------------------------------------
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);

// Debug UI
const gui = new debugUI.GUI({width: 300}).hide()

// SCENE -----------------------------------------------------------
const scene = new THREE.Scene();
// scene.add(new THREE.AxesHelper(5));

// CAMERA -----------------------------------------------------------
const cp = {
fov: 50,
ratio: window.innerWidth / window.innerHeight,
near: 0.1,
far: 1000,
};
const camera = new THREE.PerspectiveCamera(cp.fov, cp.ratio, cp.near, cp.far);

camera.position.set(0, 0, 5);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.autoRotate = true;

// const lightA = new THREE.AmbientLight(0x333333)
// scene.add(lightA)

// TEXT
const fontLoader = new FontLoader()
fontLoader.load(“…/node_modules/three/examples/fonts/helvetiker_regular.typeface.json”,
(font) => {
const textG = new TextGeometry(‘POTATO’, {
font: font,
size: 0.5,
height: 0.25,
// curveSegments: 12,
// bevelEnabled: true,
// bevelThickness: 0.2,
// bevelSize: 0.02,
// bevelOffset: 0,
// bevelSegments: 5
})

const textM = new THREE.MeshBasicMaterial()
const textMesh = new THREE.Mesh(textG,textM)
scene.add(textMesh)
})

// const guiCam = gui.addFolder(“Camera”);
// guiCam.add(camera.position, “x”, 1, 20);
// guiCam.add(camera.position, “y”, 1, 20);
// guiCam.add(camera.position, “z”, 1, 20);

// Toggle GUI Visibilty
// window.addEventListener(“keydown”, E => {
// if(E.key === ‘z’){
// (gui._hidden)? gui.show() : gui.hide()
// }
// });

window.addEventListener(“resize”, () => {
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});

// RENDER -----------------------------------------------------------

renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});

ERROR ==========================================================

PROJECT =========================================================

NOTE ============================================================

  1. Using Parcel as my package Bundler
  2. Tried 2 approaches for loading font, both not working :
    a) fontLoader.load(“…/node_modules/three/examples/fonts/helvetiker_regular.typeface.json”
    (I’ve used 2 dots, its showing 3 dots for some weird reason)
    b) fontLoader.load(“./assets/fonts/helvetiker_bold.typeface.json”

Is there an answer somewhere in this thread:

this is not a path. node_modules does not exist, you can’t fetch from it, its only purpose is to be a local dev environment which is then bundled or packed. /dist doesn’t contain node_modules, the bundled files are tree shaken and only contain the code that you use. the bundler can’t infer that you need that json file from just a string.

put static assets into /public, the path then becomes “/fonts/helvetiker_regular.typeface.json”

Well I tried that too, but no luck their either… I’m using Parcel, is there a possibility that parcel is creating this problem ?

MY CODE ===========================================================

const fontLoader = new FontLoader()
fontLoader.load(“./assets/fonts/helvetiker_bold.typeface.json”,
(font) => {
const textG = new TextGeometry(‘POTATO’, {
font: font,
size: 0.5,
height: 0.25,
// curveSegments: 12,
// bevelEnabled: true,
// bevelThickness: 0.2,
// bevelSize: 0.02,
// bevelOffset: 0,
// bevelSegments: 5
})

const textM = new THREE.MeshBasicMaterial()
const textMesh = new THREE.Mesh(textG,textM)
scene.add(textMesh)
})

PROJECT =========================================================

when you run
npm run start
parcel will bundle your project scripts into the dist folder.

Your index.js is trying to download the fonts, relative the parcel web severs webroot, which is dist by default.

Look into the dist folder and you will see the bundled files. This is what you see in the browser when you open http://localhost:1234

The fonts are not bundled. You need to manually copy them, to the dist folder. Otherwise the parcel webserver will return the default document (index.html) instead. It doesn’t actually return 404 error like most other web servers. So that is why you see Unexpected token '<', "<!DOCTYPE", etc.

The default document (index.html) is not a valid font file.

In your case, you should copy your assets folder to the dist folder so that the parcel web server can find the font files.

And then use the path "./assets/fonts/helvetiker_bold.typeface.json" in your font loader.

parcel is weird indeed. better use vite, all this bundler nonsense just evaporates.

you can’t have /src/assets, it’s not valid. the purpose of /public is that the bundler will copy it blindly into the /dist folder, which is where your app is going to live. if you have /assets inside /src nothing is going to tell the bundler that you rely on it, and it can’t know that you do rely on something with just a string "./assets/foo/...", it’s not going to attempt to make sense of strings. the bundler knows that you need something by watching your import statements. it will bundle everything that it knows you use up and throw it into /dist, and your asset folder won’t be there.

so either parcel has support for a static or public folder at the root, or it is pretty much not usable. when i google i get ridiculous results like this javascript - How do I include asset files with parcel js? - Stack Overflow they’re installing extra plugs :crazy_face:

1 Like

Is this what you mean ?

I’m trying to make sense of what you are saying… I’m relatively new :sweat_smile: Will study parcel a little more in detail…

By the way, the ./assets/<file> path is working fine while using jpg / png file, its the font file that is causing the problem :no_mouth:

Wow… moving the font file directly inside dist folder actually worked !!!
Thank you sooo much for this advice… I was stuck here since last 3 days :dizzy_face:
Thank you so much… means a lot ! :raised_hands:

OK I have a doubt now…

keeping the font file inside the assets folder is not working, but the images (jpg & png) within the same folder are getting loaded without any problem. How ???

you can’t go below the dist folder.
so ../ in your path does nothing.
Most webservers, will not serve files or navigate folders below the webroot. This is for security reasons, otherwise it would be possible to read every folder on your server looking for secrets. In parcel, the dist folder is the webroot by default.

just put your font somewhere in the dist folder, or a sub folder and then get on with your life.

if you really want the font file to be copied from the src to the dist, every time you start, then see this stackoverflow answer.

Parcel is a basic bundler, but fast. If you want all the bells & whistles, then try webpack.

But beware, the more things that you want parcel to automate for you, the slower it will be. Imagine bundling a 20gb glB into a base64 string every time you change a value in your script.