I would like to use javascript classes with one class per file. It is part of a larger project using eslint. I started with:
/*global CSReport*/
/*global CSManager*/
class CSMain {
constructor() {
this.report = new CSReport();
this.manager = new CSManager(this.report);
}
launchReport(...
}
However, eslint generates an error saying CSMain is defined but never used. This led to the idea of using export and import which seemed better than making everything global (side note: CS in front of main is the old style method to avoid global conflicts)
The question is how to put this together. The release version will be a single (uglified) file, so the class file names will no longer exist when they are all concatenated together in (say) csCompiled.js.
Questions:
Import uses a file name. Should I use the CSCompiled.js name rather than the file names before concatenation?
Do I want a single module or a module for each class?
Do I need to export every class and import every class it uses?
I am not fully sure how angular accesses this code but am thinking to import csMain.
I tried to find an answer to this but am only finding older posts that don't use ecmascript 6 and classes. If an answer to this exists, I am not sure how to get to it.
Background:
The main project uses angular 1. This code is separate for legacy reasons. It is currently written in java using gwt, but we want to move to javascript to remove the reliance on gwt. It is about 30-40 files (classes) total to convert.
The code gets and handles data from the server for report requests. There is a lot of pre-processing done before it is handed back to the rest of the UI.
I have used javascript for an established project using angular, but lack expertise on how to create new projects.
I am trying to use basic javascript for this, so it won't need updating if (for example) we go from angular 1 to the current versions. I do not yet know if this is a good way to do it.
ESLint is complaining because you are not exporting the class you created, therefore, it can't be accessed by other modules. You can fix that with a simple line at the end
export default CSMain;
Import uses a file name. Should I use the CSCompiled.js name rather
than the file names before concatenation?
Use the file name before you compile/transpile/uglify/etc. After that it will all become 1 file and the bundler will take care of that for you.
Do I want a single module or a module for each class?
Completely optional, I like to have 1 class per file and then 1 file for the module (index.js) that lists all classes in that module.
Do I need to export every class and import every class it uses?
Yes, you need to import everything your module will use and export everything that should be public or "importable" for other modules.
I am not fully sure how angular accesses this code but am thinking to import csMain.
It all depends on how you export your file. Make sure to import the same name your module/file is exporting.
Related
I'm building a client for a home-grown Node.js like backend and I'd like to support dynamic client-side JavaScript class generation. This can happen before or after Webpack but I'd prefer after (if that's doable).
In the end I'm trying to make something like this work:
import {TicTacToeGame} from 'warpdrive-client';
And have TicTacToeGame evaluate to be:
class TicTacToeGame { ... }
Except TicTacToeGame is generated by the import call or the global code in warpdrive-client based on supplied configuration or (if it's possible) an argument passed to the module at import time.
Thanks in advance.
I am using webpack to transpile/bundle/etc my js files. Im using the import/export syntax ( as opposed to the CommonJS way of require and export.module ). This means i need to import each class and all subclasses of it however many times if i need to use them in the context of a specific script.
The question:
Even though classes arent natively supported in js, why do we need to import them all the time? Wouldnt it be easier if ( and im only speaking for classes ) they were available to all scopes?
EDIT: To avoid polluting the global scope one could do something like global.myLibs and be done with that issue. I personally prefix my classes with something unique but this method would serve even those that dont i suppose.
For example:
window.myClasses could serve as a container for all my classes. I come from an iOS background where all the classes in a main "bundle", in java i think that would be a "package" are available to everyone. Re-importing the class itself doesnt seem like it serves any purpose.
See here:
Why do i need to import modules everytime in webpack bundle?
and here: Bundling js files with webpack class undefined
Adding things in the global scope can lead you to naming conflicts. What if you created a class named Node, add it to global scope by doing window.Node = Node ? You lose the reference to the browser's global Node object.
You can argue that you will never use names that are already used for global objects. But now, what if in a year or so, a new object is added to the spec with the same name as one of yours, and you want to use it alongside your own object ? You have to make a choice, or rename your own object. This is not future proof.
Importing the same module in every module that uses it is a best practice. Because by doing it, you never pollute the global scope. Don't be afraid that it imports the code of this module n times in your final bundle. Webpack imports it only one time, then uses a reference to the module everytime you are importing it.
See these resources :
JavaScript Modules: A Beginner’s Guide by Preethi Kasireddy on Medium
Eloquent Javascript Modules chapter
I need to add a hosted third-party JavaScript file in an Angular 2 component. This file is updated anytime a change is made in the associated third-party vendors proprietary system, so I cannot simply pull down a copy, include it locally, and import it into the project.
Typically I would include this file at a top level in a script tag, and then simply use declare <windowvar>: any to get access to it. However in this case, since the component itself is trying to load the script, I cannot declare the window variable because it does not exist on the window object at the time the component is loaded, which generates an error.
I can load the script by manually adding a script tag, and that works, however I need access to the window variable it creates in order to use it properly. And I cannot simply use an interval to look for it because typescript throws a fit that <windowvariable> does not exist on object window.
Is there any way I can 1) Load the hosted JavaScript file inside the component, and 2) Get access to the window variable created by the loaded JavaScript file?
Update 1: Based on the comments, the previous solution will be not help you.
You can do that by using OpaqueToken in Angular2
1. Create a Token that is used to find an instance as below in a separate ts file.
import { OpaqueToken } from '#angular/core'
export let name_of_The_Token = new OpaqueToken('name_Of_The_Window_Object');
2. In your App.module, you need to import and declare a variable that is the name of your window object which makes the Token as a angular2 service so that you can use properties, methods in that javascript file across your components.
import { name_of_The_Token } from '/* file_Path */';
declare let name_Of_The_Window_Object : any; //below your import statements
Step 3: Inject it to providers array of your module.
{ provide : name_of_The_Token , useValue : name_Of_The_Window_Object }
Guidance to use this token in components
Import the token just like any other service and #Inject from angular-core
import { name_of_The_Token } from '/* file_Path */';
import { Inject } from '#angular/core';
In constructor of the component
constructor(#Inject( name_of_The_Token ) private _serviceObject : any )
Any where in your component you can use the variables and methods of your javascript file as
this._serviceObject.method1()
this._serviceObject.variable1
.....
Note: One drawback is that you will not get intellisense.
Overcoming it:
If you are looking for intellisense you need to wrap the methods and variables inside an interface and use it in the type**(instead of any)** of your token as
export interface myCustom {
method1(args): return_Type;
method2(args): void;
.....
}
LIVE DEMO of ToasterService
Effectively, you're trying to pick up a "global module" javascript library from a CDN. (I assume the 3rd-party lib is not in CommonJS, AMD, UMD, or other module format, since it is accessed through a sole global variable.)
So the first question is where is the corresponding .d.ts file? It contains the names and interfaces that inform Typescript of the 'shape' of the library, as well as declaring that global variable will exist. If your 3rd-party doesn't provide it you'll need to write it yourself. It will contain not just the declaration of the global var, like
declare var theGlobalVarInQuestion: IInterfaceOfStuffInsideLibrary;
but also the declaration of said Interface, and its properties and their types, all the way down. Like this: https://github.com/catamphetamine/libphonenumber-js/blob/master/index.d.ts
You can include the .d.ts file in /node_modules/#types/nameOfSaidLibrary but you'd need to check it into your source repo (with possible .gitignore gymnastics) especially because a npm prune will remove it. Or if you put it elsewhere, modify the tsconfig.json typeroots property to look in both that place in addition to its usual /node_modules/#types/ folder.
Just to be clear, the .d.ts file doesn't (and shouldn't) actually create the variable; it just states that it will be there so the Typescript compiler won't complain. Whether or not it is there at runtime is decided by however you're loading the js.
If you're not loading it via script tag in the index.html, then either a Typescript import statement in the consuming component can do so (given the right config of SystemJS or whatever you're using) or the consuming component can dynamically create and append a new script tag to the index.html. Just make sure your module loader isn't trying to download and immediately bundle it with the rest of your app at buildtime. It sounds like you want the lib to be downloaded anew each time at runtime.
About a year ago I have used Meteor, and now I want to use it again, but many things have changed.
When I follow the Blaze tutorial on Meteor.com, they add imports on top of their files:
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { ReactiveDict } from 'meteor/reactive-dict';
I got the app working. But when I comment the imports out, the app keeps working like it should work. Why are these imports needed?
I am still using the regular Javascript, not ES6.
Thanks!
The import statement is used to import functions, objects or primitives that have been exported from an external module, another script, etc.
The name parameter is the name of the object that will receive the exported members. The member parameters specify individual members, while the name parameter imports all of them. name may also be a function if the module exports a single default parameter rather than a series of members. Below are examples to clarify the syntax.
Import an entire module's contents. This inserts myModule into the current scope, containing all the exported bindings from "my-module.js".
For more detail about the different ways we can use import along with their usage, please check this.
They still use the old globals for backwards compatibility. However it is recommended to use the imports so if in some future release they remove the globals your code will still work. You can read more in the appropriate section of the guide.
Ok you know import is to import an exported object from another file already.
The point that you may have missed is that MDG heard the need to stop loading everything by default, or at least to provide a mean to control what is loaded in memory and what is not.
Look for the /imports special directory.
Files in that folder are no longer loaded automatically, but only through import statement.
As for the tutorial, I guess they did not explained this functionality, and because it imports only standard functionalities which are still loaded eagerly for backward compatibility, it does not change anything removing those statements.
Does using the JavaScript import statement for images, css and others defeat the purpose of import statement which was designed to import only the JS Modules ?
Of course, for now it gets transpiled to ES5 require using webpack. But that same question comes up again. Is it incorrect to use import statement to import images or css or files ?
EDIT:
I like the idea of controlling imports that we can control the assets on build time in such a clean way - The idea that I use the image path to import the image, and
on different environments the image path would contain different values - url or path
this image can be compressed on build time
the JS module importing this image can contain the image dimensions through a custom loader
assets dependency tree is maintained at one place and un-imported items gets chucked away automatically
rebuild time is fast - DX(developer experience) would be good
I guess, this is much better than using any templating, using placeholders in the JS files to inject URLs or paths based on environment during pre-build (webpack).
But using the import statement feels not right to do so in terms of principle or semantics.
This is from Mozilla Developer Network:
The import statement is used to import functions that have been exported from an external module, another script, etc.
From everything I've read on MDN and other sources its purpose is to make a module/script methods and properties available within the current scope it's being imported into.