Alternative to require our app module each time to debug in console - javascript

When I want to debug my requirejs app, I need to reference my application everytime with something like:
var App = require('app');
as stated here:
http://requirejs.org/docs/api.html#modulenotes
From that moment I can access everything via console because the App variable points to my application instance.. However, it is very annoying to have to do it after every page refresh. Is there any alternative that would help improve the development workflow?

You could deliberately export a reference to your application into the global space. This is actually what I do. I select a name that has very little likelihood of clashing. In your app module you could do this after your App object is created: window._myproject_app = App. This is then accessible as the global _myproject_app. You can start writing the first characters and use autocomplete rather than type the whole thing when you want to access it.
If you want the export to occur only in testing you can use RequireJS' config facility to pass configuration that tells the module responsible to export the instance whether it should export it or not.

Related

How to expose a class to the global scope with esbuild?

Update
user #TKoL suggested defining a property in the window object. This produces the result I wanted to achieve, although I do not know if it is the correct way to proceed. I will be using this method for the time being. Thanks!
I am using esbuild in my project (first time using a bundler / developing JS in this "style").
The project is a small web component for which I developed a class that the end user should be able to utilize in their scripts.
// this is the component, which is then bundled and minified by esbuild.
// i have omitted various imports required in the class here.
export default class Widget extends HTMLElement {
/// code here is not relevant
}
customElements.define('custom-widget', Widget);
As it stands, the end user is able to utilize the widget from HTML like this:
<custom-widget some-custom-attribute="some-value"></custom-widget>
let widget = document.querySelector('custom-widget');
widget.someMethodDefinedInTheClass();
However, I would like to allow the user to do it all via JavaScript as well.
How can I make esbuild expose the Widget class to the global scope? I'd like to do this to enable behaviours such as:
let wOptions = {}; // object of initialization options for the widget
let widget = new Widget(wOptions);
someContainer.append(widget);
widget.someMethodDefinedInTheClass();
To make any way bundled js file to expose anything to the global scope you have to set it as a property of global object (that represents the global scope) like
globalThis.Widget = Widget;
globalThis keyword is a best way to use global object in javascript because it works the same on browser page, nodejs or service worker environment. If your code will be only executed on browser page you can also use window keyword.

How to import config vars from window in Enzyme/Sinon?

I have a react application that went from storing config vars (urls, mostly) in config files to storing those same variables in window.envs, for reasons that are out of scope for this question.
Header contains a simple script tag:
<script src="env-vars.js"></script>
Variables are laded into window
// env-vars.js
window.envs = {
QA_URL: 'qa.catdog.com'
...
}
Variables are made available to the app:
// envs.js
export default window.envs;
Then envs.js is imported into whatever component needs them.
import envs from 'config/envs';
This solution works for the app itself. Unfortunately, the change broke a lot of unit tests.
Given that the the env vars have to live in window and cannot be imported directly (at least no by the app, the unit tests can do what they want), how can I go about making window variables available to unit tests?
EDIT: the unit test stack is Enzyme/Mocha/Chai. Sinon too.

How to require plugins once and access it globally?

My app was made before the Nativescript CLI v5.x and got to a point where I needed to update CLI versions. The CLI version 5.4.2 suggests to add "tns-core-modules/" for every 'require' I have in my app since short import is deprecated in v5.2.0, since I have tons of plugins required on tons of pages, it's quite a pain in the ass changing every require line. How can I require all my plugins once and then use them on every page or anywhere I need it?
In javascript you have access to an object that always exists in the global scope, this global object provides variables and functions, the goal is to add your library to it.
You have the window object for example in a browser.
Find the global object (look post here) on your project and add your library to this object like :
var myLib = require('myLib');
var globalObject = Function('return this')();
globalObject.myLib = myLib;

Svelte framework: pass environment variables to client-side bundle at runtime

Posted this to the Svelte repo as well:
I just made my first Svelte app over the weekend, and really liked the experience. One thing I'm curious about, that I wasn't able to figure out with a decent amount of research, is if/how one could pass a runtime env var or similar to a client-side script so it's available in the bundle/browser. This probably isn't considered a "best practice", so maybe I'm just on my own here, but in Pug for example you can do something like the following (from a Hapi.js route handler for example):
const context = {
foo: bar,
baz: ''
}
return h.view('index', context)
These vars are then available in the Pug context.
In my toy app I wanted to make it possible to pass an api key at server start time (either from a .env or CLI), and inject that from the Express server like so:
app.use(express.static(`${__dirname}/public`))
and have that var be available in the client script. Again, it's probably not a best practice to be injecting api keys into client-side scripts and making calls from there, but is this kind of variable passing possible in Svelte?
It seems like this should be possible using either rollup-plugin-inject or rollup-plugin-replace, but I wasn't able to figure out how to make that work. This is definitely not a criticism of the framework, but perhaps a section on working with env vars would be a useful addition to the Svelte docs. Thanks!
Typically this is the sort of thing you would do in your build config. From the rollupjs tag I'll assume you're using that — you could use rollup-plugin-replace to inject the content you need:
// rollup.config.js
import replace from 'rollup-plugin-replace';
import svelte from 'rollup-plugin-svelte';
export default {
input: 'src/main.js',
output: {
file: 'public/bundle.js',
format: 'iife'
},
plugins: [
svelte(),
replace({
// you're right, you shouldn't be injecting this
// into a client script :)
'API_KEY': process.env.API_KEY
})
]
};

Plain Javascript as Angular 2 service

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.

Categories

Resources