Code Readability
-
@jack-waugh I've always used this super simple approach to import/export stuff in node.js. It's worked since node was new. No need to over-complicate stuff unless you are just showing off.
file: Blah.js
module.exports = { sayHello: () => { console.log('hello world'); }, sayGoodbye: () => { console.log('goodbye cruel world'); }, count: 0, showCount: () => { this.count++; console.log(this.count); } };
then in another file:
let blah = require('./Blah.js'); blah.sayHello();
-
@rob Node supports
require
, and I know how to use it there if necessary, but I believe that browsers don't natively. I think there is a package to do it, but given what year it is, I feel that use of ECMAimport
is more straightforward, as I do in the project that I am supposedly currently working on and in the framework under which I run it.For example, here are the imports from the top of the main module of the simulator.
import stdPrelude from "./utl/std_prelude.mjs"; import debug from "./utl/debug.mjs"; import CancellableWork from "./utl/cancellable_work.mjs"; import threads from "./utl/threads.mjs"; import overdom from "./utl/overdom.mjs"; import model_code from "./editable_model.mjs"; import problem_editor_view from "./problem_editor.mjs"; import validation from "./validation.mjs"; import solve from "./solve.mjs";
-
The bottom of the main module has this to export the entry points needed.
const exports = u.copy(); for (const name of t.exportNames) exports[name] = m[name]; export default exports;
Near the top, there's
const {m, u, t} = stdPrelude.clone(); t.exportNames = ['applicationStart', 'land'];
I use
m
for the work of the module,u
for utilities, andt
for temporary stuff.u.copy()
makes a copy of nothing; it is equivalent toObject.create(null)
. -
@jack-waugh And using import export is fine as well. It just seems that, in the code you posted at top (with async / await / promise stuff, exception handling, bind, tell, "combinators" etc) you are doing something else that is overly-complicated and unnecessary. At least it is unnecessary if all you are doing is trying to share code between files.
I don't put too much concern into what year it is. If something works, and it is simple to use and simple for others to understand, what value is added by doing something different?
I could teach a twelve year old my way of doing things in about 10 minutes. I consider that a plus.
-
@rob You
require(
...)
in the browser? -
@rob I agree that the import mechanism I used in the archive presenter is more complex than necessary. What I tend to do today is much simpler in most cases. As I said, I was approaching the tech as a newb back then, and hadn't come to understand the simpler way to go.
-
@jack-waugh said in Code Readability:
You require(...) in the browser?
Depends on what I'm working on. On big projects such as for work, sure. On my own smallish projects, rarely. I'm more likely to just do it like this:
File: Blah.js
Blah = { sayHello: () => { console.log('hello world'); }, sayGoodbye: () => { console.log('goodbye cruel world'); }, count: 0, showCount: () => { this.count++; console.log(this.count); } };
Then in another file:
Blah.sayHello();
-
@rob Sounds as though you are using some bundler that packages up your .js files and includes them in the HTML served.
-
@jack-waugh said in Code Readability:
Sounds as though you are using some bundler that packages up your .js files and includes them in the HTML served.
No. I've done things like that, when needed, but for simple projects there is no need.
All that is needed is:
<script src='Blah.js'></script> <script> Blah.sayHello(); </script>
where (again) Blah.js has the code like this:
Blah = { sayHello: () => { console.log('hello world'); } };
Blah is created as a global variable. I typically have one global per file. You could write it as window.Blah (which makes it more obvious it is a global in browser-space), or precede it with "var", but I often skip both of those for a clean appearance. I use upper case to make it clear that it is a global.
If I start getting worried about variable name collisions and such, then the project must have gotten huge.
I've done it sometimes like this when I worry about clashing with other variables when working in someone else's big messy app:
// create global "g" if it doesn't already exist window.g = window.g || {}; g.Blah = { sayHello: () => { console.log('hello world'); } };
And for completeness, I should add that sometimes I want a js file to run both client and server, so I might do something like this (which is admittedly a bit messier looking, but not a big deal):
{ let blah = { sayHello: () => { console.log('hello world'); } }; if(typeof window === 'undefined') { module.exports = blah; // node.js, export it } else { window.Blah = blah; // browser, make a global } }
-
@rob Yeah, I see how that would work. I had moved away from app-specific HTML for so long that I sort of forgot that you can load everything as scripts from the HTML. That technique obscures what is dependent on what. I can see that that might not matter much, but I am unused to thinking that way. I have each module import the stuff it needs.
For a future project, I may try moving from Node to Deno, which does not support
require
.My globals are
app
for the application andt
for temporary or testing. I used to only createt
by hand and not from code in a project or framework. But now I have a debugging aid callable from regular code and if called, it will uset
to place information where it can be easily gotten at via the REPL. I suppose if I wanted to be something-retentive, I could movet
toapp.t
orapp.debugging
or something. But I think future evolution of standards and tools is unlikely to grab any single-letter variables or assign meaning to them.My utility code that runs in both environments does not need to test for what environment it is running in; export works the same in either event.
The standard now has
globalThis
for the top-level global in any environment. -
@jack-waugh said in Code Readability:
That technique obscures what is dependent on what
Yeah, for stuff like that, I wait until a project becomes bigger to worry about it. It's easy to change it later if you need to be more rigorous about such things. For whatever it is worth, my suggestion is to relax a bit on such things, it might result in getting things working more quickly.
@jack-waugh said in Code Readability:
I had moved away from app-specific HTML for so long that I sort of forgot that you can load everything as scripts from the HTML.
I also do a fair amount of loading stuff this way. That is, load the script files dynamically. Can be really handy if you want to load an updated version of some code without restarting the whole app. This is a bit more complicated because it allows loading directly from a file (via src property of a script tag), or actually reading the text of the js file, and inserting that into a script tag.
(I wouldn't leave it this way on any kind of production app, but it is handy while building something out)
let loadAllJavascript = (isReload) => { var filteredPath = 'http://localhost:9999/js/filtered/'; // third item true to pull from sandbox files instead var files = [ ['ElemMaker', 'http://localhost:9999/js/library/', true], ['PopupBox', filteredPath, true], ['Scrubber', filteredPath, true], ['AccurateYoutubeTime', filteredPath, true], ['SynchronizerThread', filteredPath, true], ['VideoEventScheduler', filteredPath, true], ['VideoEventQueue', filteredPath, true], ['VideoPlayerNew', filteredPath, true] ]; for(var i=0; i<files.length; i++) { let scr = document.createElement('script'); if(files[i][2]) { if(!isReload) { // this (fetching the text then applying it // to script tag, rather than just setting the source // url) should not be necessary, but it seems to be // in this sandbox environment . fetch('./js/' + files[i][0] + '.js?' + Math.random()) .then((response) => { if (response.ok) return response.text() throw new Error('Network response was not ok.') }) .then((data) => { let scr = document.createElement('script'); scr.appendChild(document.createTextNode(data)) document.body.appendChild(scr); }); } } else { scr.src = files[i][1] + files[i][0] + '.js?' + Math.random(); document.body.appendChild(scr); } } }