Exporting one set of functions from multiple files - javascript

I've just finished writing a big quickbooks wrapper in JavaScript with a lot of parts in different files, e.g. a file for tax, a file for accounts, a file for auth, etc. I'd like to make it so that developers using this wrapper will only have to do one import that will contain all the functions I've written.
Hierarchy is something like this:
QbTax.js
QbAccounts.js
QbAuth.js
I'd like to have another file, or a way that a developer using this wrapper would only have to import one thing, then be able to call all functions from the above files from that one import.
Something like this:
import * as qb from './unifiedQbFile.js';
qb.thisIsATaxFunc();
qb.thisIsAnAccountsFunc();
qb.thisIsAnAuthFunc();
What is the best way to approach this?
The only idea I have at the moment is to write prototypes in a file (unifiedQbFile.js for instance) and export those. I'd import all the functions from my other files in that unified file then call them in my new prototypes. That seems messy though.

you can have one index.js file that exports all files then you can import that index.js file. I would personally go with this method.
// index.js
export { qbTaxFunc } from 'QBTax';
export { qbAccountsFunc } from 'QbAccounts';
export { qbAuthFunc } from 'QbAuth';
Now in some other script to import it you can do.
import qb from 'path-to-index.js';
// All functions should now be available
qb.qbTaxFunc();
qb.qbAccountsFunc();
qb.qbAuthFunc();

Related

Propper way to make a javascript library (with multiple files)

I want to make my own javascript library with some utils functions and classes for the client browser. The point its I only want to include the main file.
https://github.com/encarbassot/elioUtils.js
I've tried using the type module
having ./src/array.js, ./src/math.js, ./src/dom.js with some functions with export, thei i have two options
OPTION 1:
/lib/utils.js
import * as array from "./src/array.js"
import * as dom from "./src/dom.js"
import * as math from "./src/math.js"
export {array,dom,math}
but in the script i have to do:
script.js called from html
import {math} from "/lib/utils.js"
const {lerp} = math
the point of modules is to import only the functions you need and here i'am importing all math functions
OPTION 2:
import {zip,create2DArray} from "./src/array.js"
import {isTouchDevice,coptyToClipboard,scrollToCenter} from "./src/dom.js"
import {lerp,inverseLerp,map,clamp} from "./src/math.js"
export {zip,create2DArray,isTouchDevice,CopyToClipboard,lerp,inverseLerp,map,clamp}
but in this example every function i create in some ./src/ file i have to modify the utils.js file
also all libraries i use they dont use module, they are a big class or a big function
i thought about putting all inside a big object like
const utils = {}
utils.lerp = (start,end,amt)=>{
return (1-amt)*start+amt*end
}
// ... and more functions
or using multiple files and then compile them to the big file maybe ???
other option would be to do
document.write('<script src="/lib/src/math.js"></script>');
document.write('<script src="/lib/src/dom.js"></script>');
document.write('<script src="/lib/src/math.js"></script>');
but for what i think its not a very good practice
and last, jQuery you can import the file like a module and like a src file
and i'm trying to avoid things like webpack, i want to keep it vanila

ClassName/ClassName.js Module Resolution with Webpack & Node.js

Often times I see the following directory structure and import pattern in Javascript projects:
ClassName/index.js pattern
RepoRoot
|-src
|-index.js
|-ClassName
|-index.js
|-SupportingClass.js
src/ClassName/index.js
import { SupportingClass } from './SupportingClass';
export class ClassName {
// Implementation
}
src/index.js
import { ClassName } from './ClassName';
This is all fine and dandy. It allows for a much cleaner import of the ClassName class. However I'm not a fan of the name of the class file index.js not having the same name as the class's name. It:
Makes it harder to locate the file in a file name search (Command+P in VS Code)
You end up with just a very unhelpful index.js in the file tab in the IDE (yes I know some IDEs are smart enough to add a bit more context when you have more than one file of the same name open. That helps, but isn't a real solution imo)
Other files that aren't the indexes get much more descriptive names: SupportingClass.js, someUtils.js, etc.
ClassName/ClassName.js pattern
RepoRoot
|-src
|-index.js
|-ClassName
|-ClassName.js
|-SupportingClass.js
src/ClassName/ClassName.js
import { SupportingClass } from './SupportingClass';
export class ClassName {
// Implementation
}
src/index.js
import { ClassName } from './ClassName/ClassName';
This solves all of the problems I laid out, but makes the import of ClassName a bit duplicative. Probably not a big deal for most people especially with your IDE being able to auto import things for you nowadays.
However...
Just how webpack & node.js understand out of the box how to interpret the import path:
./ClassName as ./ClassName/index.js
Is there a setting or plugin that allows for it to interpret:
./ClassName as ./ClassName/ClassName.js?
I've been wondering for years if such a thing existed but could never really find any literature on it. Curious if anyone here knows of anything.
You are dealing with named imports and default imports, more details on this discussion can be found here:
How to import both default and named from an ES6 module
From your situation (I haven't tried with subfolders, but it should work), you may want to organize your files as such:
RepoRoot
|-src
|-index.js
|-ClassName
|-ClassName.js (named module)
|-SupportingClass.js (named module)
|-index.js (default modules)
And then you can easily import your stuff in src/index.js such as:
import ClassName, SupportingClass, { otherValues } from './ClassName'

Webpack global variable from multiple files

I'm trying to rewrite bunch of legacy JS files into module structure. I have obfuscated plugin which contains out of few files, which in turn work with single global variable. The order of execution of these files matters.
Example:
file1.js
var myModule = {someStuff};
file2.js
myModule.someProperty = someValue;
What i want to achieve is to import them all somehow and get this global variable myModule.
Possible implementation:
myModule.js
import myModule from "file1.js";
import myModule from "file2.js"; // ofc i know it does not work this way
export default class myProgramm {
constructor(){
myModule.run({options});
}
}
What i tried so far is webpack provide plugin (https://webpack.js.org/plugins/provide-plugin/), but it doesn't work with multiple files. Also i tried to use provide-multiple-plugin (adopted to webpack 4) from this gist :https://gist.github.com/shellscape/a7461022503f019598be93a512a1901a. But it seems to include files in nearly random order, so it can happen that myModule is not defined, while file2.js is executed first.

How does the JavaScript Import work under the hood?

How does the import statement actually work in JavaScript? I read the documentation and it says that it places exported code within the scope of the file. Does that mean that the code is copied over into the file where I type import?
For example - in library.js I have:
export {export function getUsefulContents(url, callback) {
getJSON(url, data => callback(JSON.parse(data)));
}
In main.js I have:
import { getUsefulContents} from 'library.js';
getUsefulContents('http://www.example.com',
data => { doSomethingUseful(data); });
This allows me to call getUsefulContents() in main.js. My question is, does main.js now have the contents that I exported from library.js?
Is using import the same as just having physically defined getUsefulContents() in main.js?
function getUsefulContents(url, callback) {
getJSON(url, data => callback(JSON.parse(data)));
}
getUsefulContents('http://www.example.com',
data => { doSomethingUseful(data); });
The main reason why I ask is because I want to know if using import will have an effect on main.js file size? Or is something else going on under the hood?
Thank you!
Depends on how you are using main.js. If you run it through a bundler, then the bundler will probably include library.js into main.js to pack it up into one file. In that case, the only advantage would be maintainability and ease of development because you are focused on the file you are working on. If you are simply running the import statement and deploying your application, the import statement won't affect the file size of main.js.
It just namespacing it within the file that you are importing it to so
any code from useful-library.js is included in the file, I visualize it this way
import { usefulCodeFromLibrary } from './useful-library.js';
((usefulCodeFromLibrary)=>{
// My excellent code
// Imported code doing it's job
usefulCodeFromLibrary.someHelperFunction()
}()

Import shared/partial module into another file

Say I have two files:
box.ts:
export module Entities {
export class Box { .. Stuff }
origin.ts:
export module Entities {
export class Origin { .. other stuff }
As I understand javascript, those two modules should merge into one module that has both my classes in it.. (I just want them in separate files for organizational reasons, but both box and origin are entities.)
So now I have a file that needs to use both of those:
service-actions.ts:
import {Entities} from '../entities/box';
import {Entities} from '../entities/origin';
... stuff that uses both of those entities.
This gives me the error:
Duplicate identifier 'Entities';
If I have one or the other, it works fine, but both fail.
Is there a way I can combine these so that the I can do Entities.Box and Entities.Origin in my service-action.ts file?
Is the only way to do this is to put Box and Origin in the same file?
Don't mix namespaces (internal modules) with external modules. See this post and this question and others for arguments against mixing. I've found it best to not use internal modules altogether. We don't gain any encapsulation benefits from namespaces. Instead, directories are a simple and solid way to organize code, and you are using them already.
entities/box.ts:
export class Box { .. Stuff }
entities/origin.ts:
export class Origin { .. other stuff }
Now instead of having to write Entities.Box, you can just import Box and use it:
import { Box } from '../entities/box';
import { Origin } from '../entities/origin';
Use as:
import {Entities as BoxEntities} from './../entities/box';
import {Entities as OriginEntities} from './../entities/origin';
// Use BoxEntities and OriginEntities here
Preferably, if you are actually exporting the classes directly from the files as you should be (and as pointed out by mk.), you could create an entities.ts file that handles it for you:
export * from './entities/box';
export * from './entities/origin';
Then import this file:
import * as Entities from './../entities';
// use Entities.Box and Entities.Origin here

Categories

Resources