Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
prom candy
Dec 16, 2005

Only I may dance
One simple and ridiculous tip for making deep copies:

code:
const myObj = { some: { deeply: ['nested', 'structure'] } }
const myObjCopy = JSON.parse(JSON.stringify(myObj))
Don't hate the player

Adbot
ADBOT LOVES YOU

gbut
Mar 28, 2008

😤I put the UN🇺🇳 in 🎊FUN🎉


prom candy posted:

One simple and ridiculous tip for making deep copies:

code:
const myObj = { some: { deeply: ['nested', 'structure'] } }
const myObjCopy = JSON.parse(JSON.stringify(myObj))
Don't hate the player

As long as you're only working with JSON-compatible objects. You can't serialize a function.

prom candy
Dec 16, 2005

Only I may dance

gbut posted:

As long as you're only working with JSON-compatible objects. You can't serialize a function.

Good reminder yeah. I don't tend to put functions inside my javascript objects but there's always like lodash.cloneDeep if someone has that need.

necrotic
Aug 2, 2005
I owe my brother big time for this!
This works in most places now https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Vino
Aug 11, 2010
The perf of that will be terrible and I hope there are no uncopyable objects in there like mutexes (do those exist in javascript?) but if you don't care about perf I applaud you.

prom candy
Dec 16, 2005

Only I may dance

Vino posted:

The perf of that will be terrible

Sir this is the javascript thread

necrotic
Aug 2, 2005
I owe my brother big time for this!

Vino posted:

The perf of that will be terrible and I hope there are no uncopyable objects in there like mutexes (do those exist in javascript?) but if you don't care about perf I applaud you.

JavaScript is single threaded so no, it has no mutexes.

Obviously don’t do deep clones in the hot paths but it’s not going to matter basically anywhere else.

MrMoo
Sep 14, 2000

prom candy posted:

One simple and ridiculous tip for making deep copies:

code:
const myObj = { some: { deeply: ['nested', 'structure'] } }
const myObjCopy = JSON.parse(JSON.stringify(myObj))
Don't hate the player

You may be able to use structuredClone().

Vino
Aug 11, 2010
OK I'm pretty sure I'm not imagining things here:

https://codesandbox.io/s/festive-shirley-sfrmd8

Basically if I have two files that both define a type and then use each other's type

a.js
code:
import { B } from "./b.js";

export class A {}

console.log(B);
let b = new B();
console.log(b);
b.js
code:
import { A } from "./a.js";

export class B {}

console.log(A);
let a = new A();
console.log(a);
You'll get:

code:
TypeError
undefined is not a constructor (evaluating 'new _a.A()')
What's happening here? Is the only solution to separate types and code? Or make a big types.ts file that re-exports all of the types?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If you put code at the top level in your file, it will run immediately when your file is loaded. That's probably not what you want, and almost certainly isn't what anybody using your file wants.

Your file should just define functions and classes and the like, and only actually do stuff when those functions are called.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
How do you go about developing multiple interdependent modules at once? So far I've been npm linking thinks. But for debugging an upcoming Electron feature (and other things), I've been running a private repo via verdaccio and installing the other projects the proper way (which also allows deduping). But that's sure a pain in the rear end when you're working on two things at once across the modules.

Can I "overwrite" modules in the module tree by npm linking after installing them as dependency?

Combat Pretzel fucked around with this message at 10:26 on Jun 25, 2023

Vino
Aug 11, 2010

Jabor posted:

If you put code at the top level in your file, it will run immediately when your file is loaded. That's probably not what you want, and almost certainly isn't what anybody using your file wants.

Your file should just define functions and classes and the like, and only actually do stuff when those functions are called.

OK but what about this

c.js
code:
import { F1 } from "./main.js"

export class C { }

export function F2() {
	F1(); // Delete this and C is no longer undefined
}
main.js
code:
import { C } from "./c.js"

export function F1() {
}

let c = new C(); // C is undefined
I'm the only one using this code, it's a small game. I don't usually write code straight into files but the one line in main.js is initializing stuff. You have to have at least one line of code in the top level or the game won't do anything right?

Anyway why is it that C is undefined? What exactly does import do if not make sure C is defined? c.js is before main.js in my index.htm file, shouldn't c.js have run first, therefore defining C, then main.js uses c, and everything is OK? Why does deleting F1() matter? I never even actually call F2()!

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Vino posted:

I'm the only one using this code, it's a small game. I don't usually write code straight into files but the one line in main.js is initializing stuff. You have to have at least one line of code in the top level or the game won't do anything right?
Your one line of code at the top level could be document.onload="let c = new C()", or in the associated HTML file do <body onload="js_main()"> or something like that.

i.e. no, you don't have to have at least one line of code in the top level. But I don't think that's what's causing your problem anyway, circular dependencies in JS suck.

Here's a really long painful explanation.

prom candy
Dec 16, 2005

Only I may dance

Vino posted:

Anyway why is it that C is undefined? What exactly does import do if not make sure C is defined? c.js is before main.js in my index.htm file, shouldn't c.js have run first, therefore defining C, then main.js uses c, and everything is OK? Why does deleting F1() matter? I never even actually call F2()!

I'm not sure how good the browser is at natively handling module imports with circular dependencies. You might need to use a build tool like Vite to package up your assets.

Doom Mathematic
Sep 2, 2008

Vino posted:

OK I'm pretty sure I'm not imagining things here:

https://codesandbox.io/s/festive-shirley-sfrmd8

Basically if I have two files that both define a type and then use each other's type

a.js
code:
import { B } from "./b.js";

export class A {}

console.log(B);
let b = new B();
console.log(b);
b.js
code:
import { A } from "./a.js";

export class B {}

console.log(A);
let a = new A();
console.log(a);
You'll get:

code:
TypeError
undefined is not a constructor (evaluating 'new _a.A()')
What's happening here? Is the only solution to separate types and code? Or make a big types.ts file that re-exports all of the types?

JavaScript is an interpreted programming language. There's no compilation step which resolves those imports prior to the execution of any of the module body code. When you script src="src/a.js" type="module", a.js is executed from top to bottom, line by line, starting with the import { B } from "./b.js"; line. When that line is executed, b.js is in turn executed from top to bottom, starting with import { A } from "./a.js";. At this point the engine could go and execute a.js, but this would cause infinite recursion and everything would explode. Instead, something else has to happen.

That something else is a little confusing if it's the first time you see it, but there's really no alternative. What the engine does is go, "Well, I've been told to import a.js - but I'm actually already in the process of importing a.js. When I started that importing process I created an internal variable _a which is intended to serve as a bucket containing all the exports from a.js. However, that object's values are all currently undefined, because I'm not done. Okay. The best I can do is press on regardless." It then continues execution, reaching export class B{} - no problem - and then console.log(A) which is implicitly console.log(_a.A), which is console.log(undefined) - no problem. Then it hits let a = new A(); which explodes in the manner seen here.

EDIT: actually _a seems to be a creation of the bundling tool you're using. Without it, you'd see a slightly different failure.

The solution is to avoid doing "real work" at import time and instead have some kind of top-level main.js which imports all the semantics it needs but doesn't export anything before actually kicking off the work you need to do.

Doom Mathematic fucked around with this message at 16:09 on Jun 25, 2023

Doom Mathematic
Sep 2, 2008

Combat Pretzel posted:

How do you go about developing multiple interdependent modules at once? So far I've been npm linking thinks. But for debugging an upcoming Electron feature (and other things), I've been running a private repo via verdaccio and installing the other projects the proper way (which also allows deduping). But that's sure a pain in the rear end when you're working on two things at once across the modules.

Can I "overwrite" modules in the module tree by npm linking after installing them as dependency?

Yes, you can npm link in the way you described.

I can also give you some unhelpful non-advice, like: if the two packages are so tightly coupled in their behaviour that they have to be developed in tandem in this way, it might be that they shouldn't be separate packages at all. Conversely, if they are truly separate packages, it should be possible for you to do the necessary work in package A, test, document and publish those changes, then switch over to package B and consume the new functionality from the new version of A as a distinct task. A good hint about when A and B can be merged is if A has no consumers other than B.

Doom Mathematic
Sep 2, 2008

Vino posted:

OK but what about this

c.js
code:
import { F1 } from "./main.js"

export class C { }

export function F2() {
	F1(); // Delete this and C is no longer undefined
}
main.js
code:
import { C } from "./c.js"

export function F1() {
}

let c = new C(); // C is undefined
I'm the only one using this code, it's a small game. I don't usually write code straight into files but the one line in main.js is initializing stuff. You have to have at least one line of code in the top level or the game won't do anything right?

Anyway why is it that C is undefined? What exactly does import do if not make sure C is defined? c.js is before main.js in my index.htm file, shouldn't c.js have run first, therefore defining C, then main.js uses c, and everything is OK? Why does deleting F1() matter? I never even actually call F2()!

Deleting the F1() call fixes this problem because it eliminates the circular dependency. When the engine is executing c.js from top to bottom, it hits the line import { F1 } from "./main.js" - normally, this causes main.js to be loaded, which causes the problem. However, the engine has already parsed the entire source file and it knows that F1 is not in use, which means it just skips that import entirely. (Actually on closer inspection I think you're using some kind of bundler which elides that import, but for the same reason.) This means there is no circular link and nothing bad happens.

By the way, importing semantics from main.js is a huge red flag, as is having main.js export stuff. Is this the top-level entry point to the application or not? This is obviously a toy example but: move F1 down into c.js, which is where it clearly belongs.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!

Doom Mathematic posted:

Yes, you can npm link in the way you described.

I can also give you some unhelpful non-advice, like: if the two packages are so tightly coupled in their behaviour that they have to be developed in tandem in this way, it might be that they shouldn't be separate packages at all. Conversely, if they are truly separate packages, it should be possible for you to do the necessary work in package A, test, document and publish those changes, then switch over to package B and consume the new functionality from the new version of A as a distinct task. A good hint about when A and B can be merged is if A has no consumers other than B.
It's mostly about the standard library I have, with tons of shared things among this and other projects.

The backend and front-end communicate either by web or by Electron IPC. For that, I wrote a bunch of abstractions to make sure the protocol over the wire is the same. So that's why the library is shared across both modules (and an interconnect library to abstract some other things, that's also shared between both main modules, but it'll disappear soon, because it's overengineering).

Combat Pretzel fucked around with this message at 19:27 on Jun 25, 2023

Vino
Aug 11, 2010
Thank you for the explanations. Makes a little bit more sense.

So this can be solved with some kind of packager? I am using npm, which packager could I use?

Or is there some way I can organize my files to keep things simpler? Like have a rule that all top level code should be in one file that has no function definitions or classes, would that work?

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Vino posted:

Thank you for the explanations. Makes a little bit more sense.

So this can be solved with some kind of packager? I am using npm, which packager could I use?

Or is there some way I can organize my files to keep things simpler? Like have a rule that all top level code should be in one file that has no function definitions or classes, would that work?
A packager won't help, and your top level file can contain whatever it wants but nothing should import from it, and no other file should do top level calls, would solve the problem.

smackfu
Jun 7, 2004

I would say I don’t run into circular imports ever so guessing you do need to organize your code better.

N.Z.'s Champion
Jun 8, 2003

Yam Slacker

Combat Pretzel posted:

How do you go about developing multiple interdependent modules at once?

Vino
Aug 11, 2010
OK it took forever but I reworked everything so that there's only one javascript file with any code at the file scope and there are no more errors. So I guess that was the answer. Thank you!

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
So I tried moving from CRA to Vite, based on posts in this thread (or the Web design one, IDK). It mostly worked. Only polyfills give me grief.

Is there an actual official guide on how to make these work? Because I keep mostly just running into blog and StackExchange posts, everyone posting different variants of vite.config.[js|ts] that seem more guesswork than anything else by their own admissions.

I think one thing that should have clued me off is that wrapping the paths in resolve: { alias: { ... } } with require.resolve made some of them work (like http, but for instance not buffer).

On my bike ride home, I pulled up a mental image of the package.json and I'm fairly certain it isn't configured as ESM. Given that I had issues with my other dependencies, that I had to convert from CommonJS back to ESM, to make them work, maybe that's the issue. Vite doesn't seem to like CommonJS.

Lumpy
Apr 26, 2002

La! La! La! Laaaa!



College Slice
CJS vs ESM: Because being a developer wasn't enough of a pain in the rear end.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
Yeh. I just changed things to CJS a few days ago to make all this poo poo able to run in Electron.

There's ongoing work to finally make Electron be able to use ESM, like normal applications, inside its main world. But the ESM resolver is (currently/still) hosed up trying to find things in an ASAR (it doesn't walk up the module tree).

El Gar
Apr 12, 2007

Hey Trophy...

Combat Pretzel posted:

How do you go about developing multiple interdependent modules at once? So far I've been npm linking thinks. But for debugging an upcoming Electron feature (and other things), I've been running a private repo via verdaccio and installing the other projects the proper way (which also allows deduping). But that's sure a pain in the rear end when you're working on two things at once across the modules.

Can I "overwrite" modules in the module tree by npm linking after installing them as dependency?

The "state of the art" right now is to use workspaces to solve this very problem. Think of it like setting up an environment where all of the workspace dependencies are "linked" into the root project by default.



Yep it's one of these.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
So long I have the package directories set up in the workspaces section of root package.json, I can refer to the packages by version number instead of path in the dependencies sections where necessary, and npm does the rest?

N.Z.'s Champion
Jun 8, 2003

Yam Slacker

Combat Pretzel posted:

So long I have the package directories set up in the workspaces section of root package.json, I can refer to the packages by version number instead of path in the dependencies sections where necessary, and npm does the rest?

Yep. Just make sure the version numbers are exactly same or else NPM won't find it and it will try to download it from NPMJS.com

docs...NPM or Yarn

El Gar
Apr 12, 2007

Hey Trophy...

N.Z.'s Champion posted:

Yep. Just make sure the version numbers are exactly same or else NPM won't find it and it will try to download it from NPMJS.com

docs...NPM or Yarn

if the workspace version is in range of any dependency request in your entire package tree it will be used


ETA: your root project will also always get the workspace no matter what you have defined in your dependencies, version is ignored in this case.

El Gar fucked around with this message at 15:00 on Jun 28, 2023

prom candy
Dec 16, 2005

Only I may dance
I'd recommend using some kind of tool for this, like Turborepo or Nx.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
I did it the manual way. It works neat. I guess I should spend more time reading documentations. The lower/deduped amount of .js files scatter-shot across the directory trees is a big plus.

prom candy posted:

I'd recommend using some kind of tool for this, like Turborepo or Nx.
Eh. Probably not. Something that bothers me about Javascript is the constant NIH and reinventing the wheel every Thursday. I'd rather avoid yet another tool, library, build or package system.

--edit:
I just looked at Turborepo, it mentions a sister project, which is yet another packer bundler, whatever. FFS.

Combat Pretzel fucked around with this message at 21:32 on Jun 28, 2023

cruft
Oct 25, 2007

Combat Pretzel posted:

I just looked at Turborepo, it mentions a sister project, which is yet another packer bundler, whatever. FFS.

prom candy posted:

Sir this is the javascript thread

prom candy
Dec 16, 2005

Only I may dance
To be fair I think that sister project is written in Rust (another JavaScript mainstay)

M31
Jun 12, 2012
In Bun/Deno/Webworkers the basic HTTP server just takes a (req: Request) -> Response function. Does anybody know if there is something similar in Node that I'm overlooking, or some NPM package that implements this?

El Gar
Apr 12, 2007

Hey Trophy...

M31 posted:

In Bun/Deno/Webworkers the basic HTTP server just takes a (req: Request) -> Response function. Does anybody know if there is something similar in Node that I'm overlooking, or some NPM package that implements this?

Unless I'm missing something you just described node's http/https server.

Combat Pretzel
Jun 23, 2004

No, seriously... what kurds?!
I'm using Fastify for this kind of stuff.

M31
Jun 12, 2012
Ah, sorry, should have been more explicit. The Node one uses Node specific request/response objects, while the other runtimes use the standardized ones (the same ones that are used in the fetch api)

Doktor Avalanche
Dec 30, 2008

use a framework (express, koa, fastify etc.)

Adbot
ADBOT LOVES YOU

El Gar
Apr 12, 2007

Hey Trophy...

M31 posted:

Ah, sorry, should have been more explicit. The Node one uses Node specific request/response objects, while the other runtimes use the standardized ones (the same ones that are used in the fetch api)

Node.js has had the fetch api since somewhere in v17 so anything v18 and above is gonna have it. If you're doing client requests just use that. If you're building an http/https server yeah find a framework you like.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply