Gatsby is a real Jamstack framework. It really works with React-powered elements that devour APIs earlier than optimizing and bundling all the pieces to function static recordsdata with bits of reactivity. That features media recordsdata, like photos, video, and audio.
The issue is that there’s no “one” approach to deal with media in a Gatsby venture. We now have plugins for all the pieces, from making queries off your native filesystem and compressing recordsdata to inlining SVGs and serving photos within the responsive picture format.
Which plugins needs to be used for sure sorts of media? How about sure use instances for sure sorts of media? That’s the place you would possibly encounter complications as a result of there are lots of plugins — some official and a few not — which are able to dealing with a number of use instances — some outdated and a few not.
That’s what this temporary two-part sequence is about. In Half 1, we mentioned varied methods and strategies for dealing with photos, video, and audio in a Gatsby venture.
This time, in Half 2, we’re protecting a unique sort of media we generally encounter: paperwork. Particularly, we’ll deal with issues for Gatsby tasks that make use of Markdown and PDF recordsdata. And earlier than wrapping up, we may even reveal an method for utilizing 3D fashions.
Fixing Markdown Complications In Gatsby
In Gatsby, Markdown recordsdata are generally used to programmatically create pages, corresponding to weblog posts. You possibly can write content material in Markdown, parse it into your GraphQL information layer, supply it into your elements, after which bundle it as HTML static recordsdata through the construct course of.
Let’s learn to load, question, and deal with the Markdown for an current web page in Gatsby.
Loading And Querying Markdown From GraphQL
Step one in your Gatsby venture is to load the venture’s Markdown recordsdata to the GraphQL information layer. We will do that utilizing the gatsby-source-filesystem plugin we used to question the native filesystem for picture recordsdata in Half 1 of this sequence.
npm i gatsby-source-filesystem
In gatsby-config.js, we declare the folder the place Markdown recordsdata will probably be saved within the venture:
module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `assets`,
path: `${ __dirname }/src/assets`,
},
},
],
};
Let’s say that we have now the next Markdown file situated within the venture’s ./src/property listing:
title: sample-markdown-file
date: 2023-07-29
—
# Pattern Markdown File
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consectetur imperdiet urna, vitae pellentesque mauris sollicitudin at. Sed id semper ex, ac vestibulum nunc. Etiam ,
bash
lorem ipsum dolor sit
## Subsection
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consectetur imperdiet urna, vitae pellentesque mauris sollicitudin at. Sed id semper ex, ac vestibulum nunc. Etiam efficitur, nunc nec placerat dignissim, ipsum ante ultrices ante, sed luctus nisl felis eget ligula. Proin sed quam auctor, posuere enim eu, vulputate felis. Sed egestas, tortor
This instance consists of two primary sections: the frontmatter and physique. It’s a widespread construction for Markdown recordsdata.
Frontmatter
Enclosed in triple dashes (—), that is an elective part at the start of a Markdown file that accommodates metadata and configuration settings for the doc. In our instance, the frontmatter accommodates details about the web page’s title and date, which Gatsby can use as GraphQL arguments.
Physique
That is the content material that makes up the web page’s primary physique content material.
We will use the gatsby-transformer-remark plugin to parse Markdown recordsdata to a GraphQL information layer. As soon as it’s put in, we might want to register it within the venture’s gatsby-config.js file:
module.exports = {
plugins: [
{
resolve: `gatsby-transformer-remark`,
options: { },
},
],
};
Restart the event server and navigate to http://localhost:8000/___graphql within the browser. Right here, we are able to mess around with Gatsby’s information layer and test our Markdown file above by making a question utilizing the title property (sample-markdown-file) within the frontmatter:
markdownRemark(frontmatter: { title: { eq: “sample-markdown-file” } }) {
html
}
}
This could return the next consequence:
“information”: {
“markdownRemark”: {
“html”: “<h1>Pattern Markdown File</h1>n<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed consectetur imperdiet urna, vitae pellentesque mauris sollicitudin at.”
// and so forth.
}
},
“extensions”: {}
}
Discover that the content material within the response is formatted in HTML. We will additionally question the unique physique as rawMarkdownBody or any of the frontmatter attributes.
Subsequent, let’s flip our consideration to approaches for dealing with Markdown content material as soon as it has been queried.
Utilizing DangerouslySetInnerHTML
dangerouslySetInnerHTML is a React function that injects uncooked HTML content material right into a part’s rendered output by overriding the innerHTML property of the DOM node. It’s thought of harmful because it basically bypasses React’s built-in mechanisms for rendering and sanitizing content material, opening up the opportunity of cross-site scripting (XSS) assaults with out paying particular consideration.
That stated, if it is advisable to render HTML content material dynamically however wish to keep away from the dangers related to dangerouslySetInnerHTML, think about using libraries that sanitize HTML enter earlier than rendering it, corresponding to dompurify.
The dangerouslySetInnerHTML prop takes an __html object with a single key that ought to include the uncooked HTML content material. Right here’s an instance:
const DangerousComponent = () => {
const rawHTML = “<p>That is <em>harmful</em> content material!</p>”;
return <div dangerouslySetInnerHTML={ { __html: rawHTML } } />;
};
To show Markdown utilizing dangerouslySetInnerHTML in a Gatsby venture, we’d like first to question the HTML string utilizing Gatsby’s useStaticQuery hook:
import { useStaticQuery, graphql } from “gatsby”;
const DangerouslySetInnerHTML = () => {
const information = useStaticQuery(graphqlquery {
markdownRemark(frontmatter: { title: { eq: “sample-markdown-file” } }) {
html
}
});
return <div></div>;
};
Now, the html property will be injected into the dangerouslySetInnerHTML prop.
import { useStaticQuery, graphql } from “gatsby”;
const DangerouslySetInnerHTML = () => {
const information = useStaticQuery(graphqlquery {
markdownRemark(frontmatter: { title: { eq: “sample-markdown-file” } }) {
html
}
});
const markup = { __html: information.markdownRemark.html };
return <div dangerouslySetInnerHTML={ markup }></div>;
};
This would possibly look OK at first, but when we have been to open the browser to view the content material, we might discover that the picture declared within the Markdown file is lacking from the output. We by no means instructed Gatsby to parse it. We do have two choices to incorporate it within the question, every with professionals and cons:
Use a plugin to parse Markdown photos.
The gatsby-remark-images plugin is able to processing Markdown photos, making them obtainable when querying the Markdown from the info layer. The principle draw back is the additional configuration it requires to set and render the recordsdata. Apart from, Markdown photos parsed with this plugin solely will probably be obtainable as HTML, so we would want to pick out a package deal that may render HTML content material into React elements, corresponding to rehype-react.
Save photos within the static folder.
The /static folder on the root of a Gatsby venture can retailer property that received’t be parsed by webpack however will probably be obtainable within the public listing. Figuring out this, we are able to level Markdown photos to the /static listing, and they are going to be obtainable wherever within the shopper. The drawback? We’re unable to leverage Gatsby’s picture optimization options to reduce the general dimension of the bundled package deal within the construct course of.
The gatsby-remark-images method might be most suited to bigger tasks since it’s extra manageable than saving all Markdown photos within the /static folder.
Let’s assume that we have now determined to go along with the second method of saving photos to the /static folder. To reference a picture within the /static listing, we simply level to the filename with none particular argument on the trail.
const StaticImage = () => {
return <img src={ “/desert.png” } alt=”Desert” />;
};
react-markdown
The react-markdown package deal supplies a part that renders markdown into React elements, avoiding the dangers of utilizing dangerouslySetInnerHTML. The part makes use of a syntax tree to construct the digital DOM, which permits for updating solely the altering DOM as a substitute of fully overwriting it. And because it makes use of comment, we are able to mix react-markdown with comment’s huge plugin ecosystem.
Let’s set up the package deal:
npm i react-markdown
Subsequent, we exchange our prior instance with the ReactMarkdown part. Nonetheless, as a substitute of querying for the html property this time, we’ll question for rawMarkdownBody after which go the consequence to ReactMarkdown to render it within the DOM.
import ReactMarkdown from “react-markdown”;
import { useStaticQuery, graphql } from “gatsby”;
const MarkdownReact = () => {
const information = useStaticQuery(graphqlquery {
markdownRemark(frontmatter: { title: { eq: “sample-markdown-file” } }) {
rawMarkdownBody
}
});
return <ReactMarkdown>{information.markdownRemark.rawMarkdownBody}</ReactMarkdown>;
};
markdown-to-jsx
markdown-to-jsx is the most well-liked Markdown part — and the lightest because it comes with none dependencies. It’s a superb instrument to think about when aiming for efficiency, and it doesn’t require comment’s plugin ecosystem. The plugin works a lot the identical because the react-markdown package deal, solely this time, we import a Markdown part as a substitute of ReactMarkdown.
npm i markdown-to-jsx
import Markdown from “markdown-to-jsx”;
import { useStaticQuery, graphql } from “gatsby”;
const MarkdownToJSX = () => {
const information = useStaticQuery(graphqlquery {
markdownRemark(frontmatter: { title: { eq: “sample-markdown-file” } }) {
rawMarkdownBody
}
});
return <Markdown> { information.markdownRemark.rawMarkdownBody }</Markdown>;
};
We now have taken uncooked Markdown and parsed it as JSX. However what if we don’t essentially wish to parse it in any respect? We’ll have a look at that use case subsequent.
react-md-editor
Let’s assume for a second that we’re creating a light-weight CMS and wish to give customers the choice to put in writing posts in Markdown. On this case, as a substitute of parsing the Markdown to HTML, we have to question it as-is.
Fairly than making a Markdown editor from scratch to resolve this, a number of packages are able to dealing with the uncooked Markdown for us. My private favourite is
react-md-editor.
Let’s set up the package deal:
npm i @uiw/react-md-editor
The MDEditor part will be imported and arrange as a managed part:
import * as React from “react”;
import { useState } from “react”;
import MDEditor from “@uiw/react-md-editor”;
const ReactMDEditor = () => {
const [value, setValue] = useState(“**Howdy world!!!**”);
return <MDEditor worth={ worth } onChange={ setValue } />;
};
The plugin additionally comes with a built-in MDEditor.Markdown part used to preview the rendered content material:
import * as React from “react”;
import { useState } from “react”;
import MDEditor from “@uiw/react-md-editor”;
const ReactMDEditor = () => {
const [value, setValue] = useState(“**Howdy world!**”);
return (
<>
<MDEditor worth={worth} onChange={ setValue } />
<MDEditor.Markdown supply={ worth } />
</>
);
};
That was a have a look at varied complications you would possibly encounter when working with Markdown recordsdata in Gatsby. Subsequent, we’re turning our consideration to a different sort of file, PDF.
Fixing PDF Complications In Gatsby
PDF recordsdata deal with content material with a totally completely different method to Markdown recordsdata. With Markdown, we simplify the content material to its most uncooked kind so it may be simply dealt with throughout completely different entrance ends. PDFs, nonetheless, are the content material offered to customers on the entrance finish. Fairly than extracting the uncooked content material from the file, we would like the person to see it as it’s, usually by making it obtainable for obtain or embedding it in a method that the person views the contents immediately on the web page, kind of like a video.
I wish to present you 4 approaches to think about when embedding a PDF file on a web page in a Gatsby venture.
Utilizing The <iframe> Aspect
The best approach to embed a PDF into your Gatsby venture is maybe by means of an iframe ingredient:
import * as React from “react”;
import samplePDF from “./property/lorem-ipsum.pdf”;
const IframePDF = () => {
return <iframe src={ samplePDF }></iframe>;
};
It’s value calling out right here that the iframe ingredient helps lazy loading (loading=”lazy”) to spice up efficiency in cases the place it doesn’t have to load straight away.
Embedding A Third-Get together Viewer
There are conditions the place PDFs are extra manageable when saved in a third-party service, corresponding to Drive, which features a PDF viewer that may embedded immediately on the web page. In these instances, we are able to use the identical iframe we used above, however with the supply pointed on the service.
const ThirdPartyIframePDF = () => {
return (
<iframe
src=”https://drive.google.com/file/d/1IiRZOGib_0cZQY9RWEDslMksRykEnrmC/preview”
allowFullScreen
title=”PDF Pattern in Drive”
/>
);
};
It’s an excellent reminder that you just wish to belief the third-party content material that’s served in an iframe. If we’re successfully loading a doc from another person’s supply that we don’t management, your website may turn into liable to safety vulnerabilities ought to that supply turn into compromised.
Utilizing react-pdf
The react-pdf package deal supplies an interface to render PDFs as React elements. It’s based mostly on pdf.js, a JavaScript library that renders PDFs utilizing HTML Canvas.
To show a PDF file on a <canvas>, the react-pdf library exposes the Doc and Web page elements:
Doc: Masses the PDF handed in its file prop.
Web page: Shows the web page handed in its pageNumber prop. It needs to be positioned inside Doc.
We will set up to our venture:
npm i react-pdf
Earlier than we put react-pdf to make use of, we might want to arrange a service employee for pdf.js to course of time-consuming duties corresponding to parsing and rendering a PDF doc.
import { pdfjs } from “react-pdf”;
pdfjs.GlobalWorkerOptions.workerSrc = “https://unpkg.com/pdfjs-dist@3.6.172/construct/pdf.employee.min.js”;
const ReactPDF = () => {
return <div></div>;
};
Now, we are able to import the Doc and Web page elements, passing the PDF file to their props. We will additionally import the part’s essential types whereas we’re at it.
import { Doc, Web page } from “react-pdf”;
import { pdfjs } from “react-pdf”;
import “react-pdf/dist/esm/Web page/AnnotationLayer.css”;
import “react-pdf/dist/esm/Web page/TextLayer.css”;
import samplePDF from “./property/lorem-ipsum.pdf”;
pdfjs.GlobalWorkerOptions.workerSrc = “https://unpkg.com/pdfjs-dist@3.6.172/construct/pdf.employee.min.js”;
const ReactPDF = () => {
return (
<Doc file={ samplePDF }>
<Web page pageNumber={ 1 } />
</Doc>
);
};
Since accessing the PDF will change the present web page, we are able to add state administration by passing the present pageNumber to the Web page part:
import { useState } from “react”;
// …
const ReactPDF = () => {
const [currentPage, setCurrentPage] = useState(1);
return (
<Doc file={ samplePDF }>
<Web page pageNumber={ currentPage } />
</Doc>
);
};
One problem is that we have now pagination however don’t have a approach to navigate between pages. We will change that by including controls. First, we might want to know the variety of pages within the doc, which is accessed on the Doc part’s onLoadSuccess occasion:
const ReactPDF = () => {
const [pageNumber, setPageNumber] = useState(null);
const [currentPage, setCurrentPage] = useState(1);
const handleLoadSuccess = ({ numPages }) => {
setPageNumber(numPages);
};
return (
<Doc file={ samplePDF } onLoadSuccess={ handleLoadSuccess }>
<Web page pageNumber={ currentPage } />
</Doc>
);
};
Subsequent, we show the present web page quantity and add “Subsequent” and “Earlier” buttons with their respective handlers to alter the present web page:
const ReactPDF = () => {
const [currentPage, setCurrentPage] = useState(1);
const [pageNumber, setPageNumber] = useState(null);
const handlePrevious = () => {
// checks if it is not the primary web page
if (currentPage > 1) {
setCurrentPage(currentPage – 1);
}
};
const handleNext = () => {
// checks if it is not the final web page
if (currentPage < pageNumber) {
setCurrentPage(currentPage + 1);
}
};
const handleLoadSuccess = ({ numPages }) => {
setPageNumber(numPages);
};
return (
<div>
<Doc file={ samplePDF } onLoadSuccess={ handleLoadSuccess }>
<Web page pageNumber={ currentPage } />
</Doc>
<button onClick={ handlePrevious }>Earlier</button>
<p>{currentPage}</p>
<button onClick={ handleNext }>Subsequent</button>
</div>
);
};
This supplies us with all the pieces we have to embed a PDF file on a web page through the HTML <canvas> ingredient utilizing react-pdf and pdf.js.
There may be one other related package deal able to embedding a PDF file in a viewer, full with pagination controls. We’ll have a look at that subsequent.
Utilizing react-pdf-viewer
Not like react-pdf, the react-pdf-viewer package deal supplies built-in customizable controls proper out of the field, which makes embedding a multi-page PDF file rather a lot simpler than having to import them individually.
Let’s set up it:
Since react-pdf-viewer additionally depends on pdf.js, we might want to create a service employee as we did with react-pdf, however provided that we aren’t utilizing each packages on the similar time. This time, we’re utilizing a Employee part with a workerUrl prop directed on the employee’s package deal.
import { Employee } from “@react-pdf-viewer/core”;
const ReactPDFViewer = () => {
return (
<>
<Employee workerUrl=”https://unpkg.com/pdfjs-dist@3.4.120/construct/pdf.employee.min.js”></Employee>
</>
);
};
Notice {that a} employee like this should be set simply as soon as on the format stage. That is very true should you intend to make use of the PDF viewer throughout completely different pages.
Subsequent, we import the Viewer part with its types and level it on the PDF by means of its fileUrl prop.
import { Viewer, Employee } from “@react-pdf-viewer/core”;
import “@react-pdf-viewer/core/lib/types/index.css”;
import samplePDF from “./property/lorem-ipsum.pdf”;
const ReactPDFViewer = () => {
return (
<>
<Viewer fileUrl={ samplePDF } />
<Employee workerUrl=”https://unpkg.com/pdfjs-dist@3.6.172/construct/pdf.employee.min.js”></Employee>
</>
);
};
As soon as once more, we have to add controls. We will try this by importing the defaultLayoutPlugin (together with its corresponding types), making an occasion of it, and passing it within the Viewer part’s plugins prop.
import { Viewer, Employee } from “@react-pdf-viewer/core”;
import { defaultLayoutPlugin } from “@react-pdf-viewer/default-layout”;
import “@react-pdf-viewer/core/lib/types/index.css”;
import “@react-pdf-viewer/default-layout/lib/types/index.css”;
import samplePDF from “./property/lorem-ipsum.pdf”;
const ReactPDFViewer = () => {
const defaultLayoutPluginInstance = defaultLayoutPlugin();
return (
<>
<Viewer fileUrl={ samplePDF } plugins={ [defaultLayoutPluginInstance] } />
<Employee workerUrl=”https://unpkg.com/pdfjs-dist@3.6.172/construct/pdf.employee.min.js”></Employee>
</>
);
};
Once more, react-pdf-viewer is an alternative choice to react-pdf that may be just a little simpler to implement should you don’t want full management over your PDF recordsdata, simply the embedded viewer.
There may be another plugin that gives an embedded viewer for PDF recordsdata. We’ll have a look at it, however solely briefly, as a result of I personally don’t suggest utilizing it in favor of the opposite approaches we’ve coated.
Why You Shouldn’t Use react-file-viewer
The final plugin we’ll try is react-file-viewer, a package deal that provides an embedded viewer with a easy interface however with the capability to deal with quite a lot of media along with PDF recordsdata, together with photos, movies, PDFs, paperwork, and spreadsheets.
import FileViewer from “react-file-viewer”;
const PDFReactFileViewer = () => {
return <FileViewer fileType=”pdf” filePath=”/lorem-ipsum.pdf” />;
};
Whereas react-file-viewer will get the job executed, this can be very outdated and will simply create extra complications than it solves with compatibility points. I counsel avoiding it in favor of both an iframe, react-pdf, or react-pdf-viewer.
Fixing 3D Mannequin Complications In Gatsby
I wish to cap this temporary two-part sequence with another media sort which may trigger complications in a Gatsby venture: 3D fashions.
A 3D mannequin file is a digital illustration of a three-dimensional object that shops details about the item’s geometry, texture, shading, and different properties of the item. On the net, 3D mannequin recordsdata are used to boost person experiences by bringing interactive and immersive content material to web sites. You might be more than likely to come across them in product visualizations, architectural walkthroughs, or academic simulations.
There’s a multitude of 3D mannequin codecs, together with glTF OBJ, FBX, STL, and so forth. We’ll use glTF fashions for an illustration of a headache-free 3D mannequin implementation in Gatsby.
The GL Transmission Format (glTF) was designed particularly for the online and real-time purposes, making it very best for our instance. Utilizing glTF recordsdata does require a selected webpack loader, so for simplicity’s sake, we’ll save the glTF mannequin within the /static folder on the root of our venture as we have a look at two approaches to create the 3D visible with Three.js:
Utilizing a vanilla implementation of Three.js,
Utilizing a package deal that integrates Three.js as a React part.
Utilizing Three.js
Three.js creates and masses interactive 3D graphics immediately on the net with the assistance of WebGL, a JavaScript API for rendering 3D graphics in real-time inside HTML <canvas> components.
Three.js will not be built-in with React or Gatsby out of the field, so we should modify our code to assist it. A Three.js tutorial is out of scope for what we’re discussing on this article, though wonderful studying assets can be found within the Three.js documentation.
We begin by putting in the three library to the Gatsby venture:
npm i three
Subsequent, we write a operate to load the glTF mannequin for Three.js to reference it. This implies we have to import a GLTFLoader add-on to instantiate a brand new loader object.
import * as React from “react”;
import * as THREE from “three”;
import { GLTFLoader } from “three/addons/loaders/GLTFLoader.js”;
const loadModel = async (scene) => {
const loader = new GLTFLoader();
};
We use the scene object as a parameter within the loadModel operate so we are able to connect our 3D mannequin as soon as loaded to the scene.
From right here, we use loader.load() which takes 4 arguments:
The glTF file location,
A callback when the useful resource is loaded,
A callback whereas loading is in progress,
A callback for dealing with errors.
import * as THREE from “three”;
import { GLTFLoader } from “three/addons/loaders/GLTFLoader.js”;
const loadModel = async (scene) => {
const loader = new GLTFLoader();
await loader.load(
“/strawberry.gltf”, // glTF file location
operate (gltf) {
// known as when the useful resource is loaded
scene.add(gltf.scene);
},
undefined, // known as whereas loading is in progress, however we aren’t utilizing it
operate (error) {
// known as when loading returns errors
console.error(error);
}
);
};
Let’s create a part to host the scene and cargo the 3D mannequin. We have to know the ingredient’s shopper width and top, which we are able to get utilizing React’s useRef hook to entry the ingredient’s DOM properties.
import * as THREE from “three”;
import { useRef, useEffect } from “react”;
// …
const ThreeLoader = () => {
const viewerRef = useRef(null);
return <div fashion={ { top: 600, width: “100%” } } ref={ viewerRef }></div>; // Provides the ingredient its dimensions
};
Since we’re utilizing the ingredient’s clientWidth and clientHeight properties, we have to create the scene on the shopper facet inside React’s useEffect hook the place we configure the Three.js scene with its essential enhances, e.g., a digital camera, the WebGL renderer, and lights.
const { present: viewer } = viewerRef;
const scene = new THREE.Scene();
const digital camera = new THREE.PerspectiveCamera(75, viewer.clientWidth / viewer.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(viewer.clientWidth, viewer.clientHeight);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.place.set(0, 0, 5);
scene.add(directionalLight);
viewer.appendChild(renderer.domElement);
renderer.render(scene, digital camera);
}, []);
Now we are able to invoke the loadModel operate, passing the scene to it as the one argument:
const { present: viewer } = viewerRef;
const scene = new THREE.Scene();
const digital camera = new THREE.PerspectiveCamera(75, viewer.clientWidth / viewer.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(viewer.clientWidth, viewer.clientHeight);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.place.set(0, 0, 5);
scene.add(directionalLight);
loadModel(scene); // Right here!
viewer.appendChild(renderer.domElement);
renderer.render(scene, digital camera);
}, []);
The final a part of this vanilla Three.js implementation is so as to add OrbitControls that permit customers to navigate the mannequin. Which may look one thing like this:
import * as THREE from “three”;
import { useRef, useEffect } from “react”;
import { OrbitControls } from “three/examples/jsm/controls/OrbitControls”;
import { GLTFLoader } from “three/addons/loaders/GLTFLoader.js”;
const loadModel = async (scene) => {
const loader = new GLTFLoader();
await loader.load(
“/strawberry.gltf”, // glTF file location
operate (gltf) {
// known as when the useful resource is loaded
scene.add(gltf.scene);
},
undefined, // known as whereas loading is in progress, however it’s not used
operate (error) {
// known as when loading has errors
console.error(error);
}
);
};
const ThreeLoader = () => {
const viewerRef = useRef(null);
useEffect(() => {
const { present: viewer } = viewerRef;
const scene = new THREE.Scene();
const digital camera = new THREE.PerspectiveCamera(75, viewer.clientWidth / viewer.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(viewer.clientWidth, viewer.clientHeight);
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.place.set(0, 0, 5);
scene.add(directionalLight);
loadModel(scene);
const goal = new THREE.Vector3(-0.5, 1.2, 0);
const controls = new OrbitControls(digital camera, renderer.domElement);
controls.goal = goal;
viewer.appendChild(renderer.domElement);
var animate = operate () {
requestAnimationFrame(animate);
controls.replace();
renderer.render(scene, digital camera);
};
animate();
}, []);
<div fashion={ { top: 600, width: “100%” } } ref={ viewerRef }></div>;
};
That could be a straight Three.js implementation in a Gatsby venture. Subsequent is one other method utilizing a library.
Utilizing React Three Fiber
react-three-fiber is a library that integrates the Three.js with React. One in all its benefits over the vanilla Three.js method is its skill to handle and replace 3D scenes, making it simpler to compose scenes with out manually dealing with intricate points of Three.js.
We start by putting in the library to the Gatsby venture:
npm i react-three-fiber @react-three/drei
Discover that the set up command consists of the @react-three/drei package deal, which we’ll use so as to add controls to the 3D viewer.
I personally love react-three-fiber for being tremendously self-explanatory. For instance, I had a comparatively straightforward time migrating the intensive chunk of code from the vanilla method to this a lot cleaner code:
import { useLoader, Canvas } from “@react-three/fiber”;
import { OrbitControls } from “@react-three/drei”;
import { GLTFLoader } from “three/examples/jsm/loaders/GLTFLoader”;
const ThreeFiberLoader = () => {
const gltf = useLoader(GLTFLoader, “/strawberry.gltf”);
return (
<Canvas digital camera={ { fov: 75, close to: 0.1, far: 1000, place: [5, 5, 5] } } fashion={ { top: 600, width: “100%” } }>
<ambientLight depth={ 0.4 } />
<directionalLight coloration=”white” />
<primitive object={ gltf.scene } />
<OrbitControls makeDefault />
</Canvas>
);
};
Due to react-three-fiber, we get the identical consequence as a vanilla Three.js implementation however with fewer steps, extra environment friendly code, and a slew of abstractions for managing and updating Three.js scenes.
Two Remaining Suggestions
The very last thing I wish to go away you with is 2 closing issues to bear in mind when working with media recordsdata in a Gatsby venture.
Bundling Property By way of Webpack And The /static Folder
Importing an asset as a module so it may be bundled by webpack is a typical technique so as to add post-processing and minification, in addition to hashing paths on the shopper. However there are two further use instances the place you would possibly wish to keep away from it altogether and use the static folder in a Gatsby venture:
Referencing a library exterior the bundled code to forestall webpack compatibility points or an absence of particular loaders.
Referencing property with a selected identify, for instance, in an internet manifest file.
You’ll find a detailed rationalization of the static folder and use it to your benefit within the Gatsby documentation.
Embedding Information From Third-Get together Providers
Secondly, you’ll be able to by no means be too cautious when embedding third-party companies on an internet site. Changed content material components, like <iframe>, can introduce varied safety vulnerabilities, significantly once you would not have management of the supply content material. By integrating a 3rd get together’s scripts, widgets, or content material, an internet site or app is liable to potential vulnerabilities, corresponding to iframe injection or cross-frame scripting.
Furthermore, if an built-in third-party service experiences downtime or efficiency points, it may immediately impression the person expertise.
Conclusion
This text explored varied approaches for working round widespread complications it’s possible you’ll encounter when working with Markdown, PDF, and 3D mannequin recordsdata in a Gatsby venture. Within the course of, we leveraged a number of React plugins and Gatsby options that deal with how content material is parsed, embed recordsdata on a web page, and handle 3D scenes.
That is additionally the second article in a short two-part sequence that addresses widespread complications working with quite a lot of media sorts in Gatsby. The first half covers extra widespread media recordsdata, together with photos, video, and audio.
When you’re in search of extra cures to Gatsby complications, please try my different two-part sequence that investigates internationalization.
See Additionally
“Gatsby Complications And How To Treatment Them: i18n (Half 1)”
“Gatsby Complications And How To Treatment Them: i18n (Half 2)”
“Gatsby Complications And How To Treatment Them: Media Information (Half 1)”
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!