Babel / Node / Relay / Webpack cache? - node.js

Generally:
Do these four systems have caches? And if so, what is the method for clearing each?
Specifically:
Having trouble with a react app we are developing. Seemingly sporadically we get the following error when developing locally:
"Invariant Violation: RelayQL: Unexpected invocation at runtime. Either the Babel transform was not set up, or it failed to identify this call site. Make sure it is being used verbatim as `Relay.QL`."
Am yet to notice any particular reason why/when this starts happening.
I finally found a hack solution which involved me going into the referenced component file referenced (further in the error msg, unshown) and deleting the RelayQL fragment inside e.g.
export default Relay.createContainer(PinterestShare, {
fragments: {
resource: () => Relay.QL`
fragment on Resource {
id
title
files {
type
images {
medium { url width }
}
}
}
`
}
});
to
export default Relay.createContainer(PinterestShare, {
fragments: {
resource: () => Relay.QL`
`
}
});
I then save, and reboot the app. It crashes, obviously, as the fragment is malformed. So I undo the change back to the original, and reboot the app again. Now, the original error is fixed, despite no code actually changing.
So what happened? Somehow doing this process is flushing some cache? Is this in node, webpack, relay, or babel? I've tried rebooting my machine inbetween, as well as killall node, neither which work, which implies to me it is not RAM based...
The annoying part now is I am having to do this for all of my individual component files. Surely there must be a way to purge this mystery cache enmass for the whole app?

Related

Crypto.randomUUID() not working with Next.js v13

The Environment
Next.js v13 (stable, no ./app folder) is running with Node v18 in Ubuntu WSL.
As per de docs , the Crypto API has been around since Node v14~ish.
This has been indeed tested in Node, in my environment:
Node 18 importing and running crypto.randomUUID()
I also printed the whole object and it looks as the docs says it should.
The Problem
Imagine this simple component:
import crypto from 'crypto';
export default function Crypto() {
console.log(crypto);
return (
<p>
{crypto.randomUUID()}
</p>
);
}
Next.js says it "compiled client and server successfully in 397 ms". But after the UUID renders in the browser for a couple of milliseconds, Next.js throws a couple of errors revolving around randomUUID not being a function.
Next Runtime Error with crypto.randomUUID()
I see that Webpack is somewhat mingling in there; haven't tried Turbopack. It's beyond the scope of this issue.
After commenting out the method invocation within the paragraph, the console.log(crypto) runs and prints twice, as usual, in the devtools as follows:
crypto method printed
Notice how one comes from "react devetools backend" and the other one from webkpack. That leads me to believe the error gets thrown server-side as the console.loglog is invoked before the UUID method.
Server-side, despite the errors thrown in the browser, the object gets printed by the Next CLI and it contains the method: Next CLI prints crypto object and randomUUID is listed
Client-side, within the printed object, the method randomUUID() is nowhere to be found:
Inside printed crypto object in devtools
This confirms the error message. My code is not getting access to the method. Also, a couple of methods are missing, when compared to the Node docs.
And yet if one console.log(crypto) directly from the devTools, it has indeed the method within its prototype:
randomUUID directly from devtools
Furthermore, because of the structure, I'm inclined to believe the crypto object being printed is somehow coming from Node, as the structure of the Chrome V8 crypto object is completely different. But why in the hell are those methods missing?
I tried console.loging the object server-side, client-side, and in-between. Somehow the method gets lost in-between. Webpack might be the culprit. Worst of all, albeit being for the blink of an eye, I can see the string rendered before the errors get thrown; and dismissing the error cards throws a blank body. The string disappears.
EDIT
The reason one imports/requires crypto is so it can run in Node. Next is a SSR framework; in a nutshell it is intended to run first on the server, get rendered and delivered as HTML as much as it can to the client. If not imported, Node throws an error when Next tries to invoke Crypto server-side.
Now then, I tell that piece of code to only run if the Window object is available (i.e. I'm in the Browser) and it runs with the native chromium V8 Crypto object.
// import crypto from 'crypto';
export default function Crypto() {
if (typeof window !== 'undefined') {
console.log('CLIENT: ', crypto.randomUUID());
return (
<p>
{crypto.randomUUID()}
</p>
);
}
return (
<h1>SERVER SIDE</h1>
);
}
The only downside is that is somehow still runs twice bc of Next magic, once server side and one client-side, which means it's not bc of React 18. It tells me accurately that which is to be expected as an UUID function always returns a different result.
Browsers restrict access to some crypto APIs when not running in a secure context (as defined here).
Set it to state in a useEffect hook when page initially loads so it persist and then render it from state.
const Crypto = () => {
const [randomUUID, setRandomUUID] = useState();
useEffect((
if (typeof window !== 'undefined' && !randomUUID) {
setRandomUUID(crypto.randomUUID());
}
),[]);
if(!randomUUID) <>No UUID</>;
return <>{randomUUID}</>
}
export default Crypto;

How to create a static website generator in React

Tech stack - Node.js, MongoDB for the database, Strapi CMS for editing and API, React - my application.
I have a database with a long list of entries and a ready-to-use application that allows users to read data from the database. I need to be able to generate a simple website with a single entity from my database as a source to fill the template.
Mockup
Here is a mock-up. Hopefully, it will make things a bit clearer.
Clarification
After a day of thinking about the task, I believe I need something like a simplest static website generator - an application that will allow me to select a single bit of data from the list and generate a small website filled with it. The end goal is to get a website in some subfolder of my application where I can get it and use it however I need.
A bit more about specifics:
It will be used locally
Security can be neglected
Running always in development is not a problem (just in case, thinking about additional question #2)
Few additional questions:
Is it possible to run NPM scripts from the application (like npm build)
Is there any way to show one component in development mode, but replace it with another during building for production?
App.js
//...
function App() {
if() {
return <AdminUI /> // This one is to be shown in development mode
} else {
return <Website /> // This one is to be used instead of AdminUI in the build
}
UPDATE
Well, I'm digging a path to create a site generator and so far I come up with the following basic plan:
Get my template ready
Create a new directory for my website
Copy a template to the new folder
Get an HTML file, parse it to a string to modify
Swap some bits with my data
Save to a file from the modified string
repeat if needed for other files.
If that works as expected, the whole process probably might be improved by moving from a fixed template to a component, that will be prepared with a JavaScript bundler and started with the help of something like node-cmd (to run shell commands from my application)...
What you want could be achievable, but if it's just a string and little else, I'd say it's much simpler to fetch the data at startup from a given file, and populate from there. You can put a JSON file under the public folder (together with other static data, like images) and have the file being your configuration.
In the App.js file, write an async componentDidMount() and you can do an await axios.get("") with your configuration.
So App.js would look like (code written on the fly, didn't check in an IDE):
export class App extends React.App {
constructor(props) {
super(props);
this.state = { loading: true, };
}
async componentDidMount() {
const response = await axios.get("your/data.json");
this.setState({ loading: false, ... whatever})
}
render = () => (
<>
(this.state.loading && <div>Still loading...</div>)
(this.state.adminData && <AdminUI data={this.state.admingData} />)
(this.state.devData && <Website data={this.state.devData} />)
</>
)
}
If you don't care about security, wouldn't be much simpler like this? And if you use TypeScript you'll have a much much simpler life in handling the data too.
Maybe it's worth doing an AdminUI to generate the JSON, and the another UI which reads the JSON, so you end up doing two UIs. The template-generated UI could even ask for a JSON file to bootstrap directly to the user, if it simplifies... In general, an approach based on simple JSON sounds a lost simpler than going for a CI/CD pipeline.

Retrieve file contents during Gatsby build

I need to pull in the contents of a program source file for display in a page generated by Gatsby. I've got everything wired up to the point where I should be able to call
// my-fancy-template.tsx
import { readFileSync } from "fs";
// ...
const fileContents = readFileSync("./my/relative/file/path.cs");
However, on running either gatsby develop or gatsby build, I'm getting the following error
This dependency was not found:
⠀
* fs in ./src/templates/my-fancy-template.tsx
⠀
To install it, you can run: npm install --save fs
However, all the documentation would suggest that this module is native to Node unless it is being run on the browser. I'm not overly familiar with Node yet, but given that gatsby build also fails (this command does not even start a local server), I'd be a little surprised if this was the problem.
I even tried this from a new test site (gatsby new test) to the same effect.
I found this in the sidebar and gave that a shot, but it appears it just declared that fs was available; it didn't actually provide fs.
It then struck me that while Gatsby creates the pages at build-time, it may not render those pages until they're needed. This may be a faulty assessment, but it ultimately led to the solution I needed:
You'll need to add the file contents to a field on File (assuming you're using gatsby-source-filesystem) during exports.onCreateNode in gatsby-node.js. You can do this via the usual means:
if (node.internal.type === `File`) {
fs.readFile(node.absolutePath, undefined, (_err, buf) => {
createNodeField({ node, name: `contents`, value: buf.toString()});
});
}
You can then access this field in your query inside my-fancy-template.tsx:
{
allFile {
nodes {
fields { content }
}
}
}
From there, you're free to use fields.content inside each element of allFile.nodes. (This of course also applies to file query methods.)
Naturally, I'd be ecstatic if someone has a more elegant solution :-)

Phaser problem: loading images imported from files as base64 data

I have trouble loading image(s) as Base64 data. In the following code (partially borrowed from here), the 'loading' function this.textures.addBase64 is used:
import bgSrc from '../assets/img/back.png';
...
create() {
this.numToLoad = 1;
this.textures.on('addtexture', () => {
console.log('another image loaded')
this.numToLoad--;
if (this.numToLoad < 1) this.createNext();
})
this.textures.addBase64('background', bgSrc);
...
}
createNext() {
//...use the images
}
However, the 'addtexture' event never fires. And the image, loaded this way, never loads, no matter how long I wait.
But everything goes fine if I use direct Base64 code, like const bgSrc = 'data:image/png;base64, blablablah' instead of import bgSrc from '../assets/img/back.png'. So the problem is in importing the image.
I use phaser 3 webpack in this project. plus url-loader. Maybe the url-loader is incorrectly set up? I am not sure if the url-loader is even needed for performing npm run start.
Well, it was indeed an incorrect setup of the url-loader. (I used one more plugin in the webpack, and they didn't work well together.)
So, the code above is OK after all.

Parsing errors appear randomly and temporarily

I am working on a small react app and every so often after I save a file, the code won't compile due to some parsing error on a line that I didn't change and had not been previously problematic. A workaround I have found is to delete a random semicolon, save, put the semicolon back and save again which then allows my app to recompile without issue.
I've pasted some code below that now apparently has errors. I've also pasted an image of my error message in the browser. Seems to be related to my destructuring perhaps?
I have tried running npm install again but that didn't solve the issue. I am running node version v6.11.3 and react version 16.7.0,
I would like to solve this mysterious issue -- has anyone else have this happen to them?
maybeRenderCalendar() {
const { openCalendar } = this.state;
if (!openCalendar) {
return null;
}
return (
<Calendar />
);
}

Resources