Access webpack modules / variables from global scope - javascript

I have my react application compiled through from webpack. I'm using google recaptca's callback url like so:
<script defer src='https://www.google.com/recaptcha/api.js?render=explicit&onload=mywebpackfn'></script>
mywebpackfn is defined inside my webpack compiled js file. api.js can't find it. How can I get access to the webpack js scope from outside?

You could simply expose your function to global scope. Inside your code
if( typeof window !== 'undefined' ) { // browser env
window.mywebpackfn = yourFunction
}
Or something fancy to access global scope
// I know kung fu
(new Function('return this')()).mywebpackfn = yourFunction
Also you might want to compile your code as library https://webpack.js.org/configuration/output/#output-library
Webpack config
output: {
..
library: 'mywebpackfn',
libraryTarget: 'window'
}

If you are familiar with nodejs then you can create your node server outside of that webpack and api.js. In such a way that node server will be common to both webpack and api.js.
In that way you can export your file from webpack that will still be required by api.js by that nodejs server.
Hope this will help.

If you want to keep things controlled via webpack, rather than assign to window directly in your codebase, you can use the expose-loader
https://github.com/webpack-contrib/expose-loader
Or you can specify the output.library option of webpack which will expose the exports of your entry file as an object in global scope - you could export your callback from there

Related

Webpack - How to reuse global library name when it already exists?

Good evening!
I have this monorepo with multiple packages, where each of them is bundled independently using Webpack.
Before it was a monorepo, I would have a single bundle file, and it would be possible to have it available through a global variable within the browser through output.library property. Now I have the following since I have multiple entries:
output: {
library: "SC",
// export itself to UMD format
libraryTarget: "umd",
umdNamedDefine: true,
filename: "[name]/dist/organization-[name].js",
// fix for https://github.com/webpack/webpack/issues/6525
globalObject: `(typeof self !== 'undefined' ? self : this)`
}
The problem is that if I use this same config for every package, and I import more than one to the browser using script tags, only the latest script will actually be available because it's essentially recreating the global variable each time.
Is there a way to reuse it? Or maybe a better convention I could use here.
In node, for instance, I import each of them using the bundle name, but in the browser, I feel like it should all be under the same global variable.
Thank you for any suggestions!
As mentioned in the issue I created over webpack's repository, the solution is to use the following:
library: ["MyLibrary", "[name]"]
That will make all packages available under the same global variable MyLibrary but separated by their respective entry (i.e., MyLibrary.entryOne and MyLibrary.entryTwo).

Properties file in JavaScript / Angular

In Java I usually create application.properties in my resource folder and put configs in there.
And when I need it I just do Properties prop = new Properties(); prop.load(... my file) and then use prop.getProperty("Something")
I want to do something similar in Javascript
In my js code I have this:
// REST API Base URL
var baseUrl = "http://localhost:8083/api";
I want this to be in a application.properties file and then load the value.
How can I achive this?
Thanks
In angular 2+ projects and for a good practices you should create environments folder with one file per env like: environment.js, environment.prod.js.
and into file you can export a constant or by default like that
export const environment = {
apiUrl: '',
googleApiKey: '',
}
and you can import this environment in every file you will needed like
import { environment } from '{relativePath}/environment/environment.js'
If you create different files for every env like prod. You need to replace environment.js for env that you will be build. You have lot of info about this with webpack or other compilers.
I recommend you strongly to develop into a common.js project. It will be more friendly for you importing modules and you will have powerful possibilities of scalable app.
But the easy(Ugly) solution is:
index.html
<head>
<script src="environment.js">
<script src="app.js">
</head>
environment.js
// Declaring environment like that you will have window scoped the variable
// and you will have global access to environment with window.environment
var environment = {apiUrl: 'https://api.url:4100'}
app.js
function example(){
console.log(window.environment.apiUrl); // out https://api.url:4100
}
The approach depends on how you build and/or bundle your AngularJs application. But regardless of that, you'll need to create a config.json file to contain your settings.
If using browserify or webpack, you can import that file via require(...), otherwise you can simply request it via ajax before your app bootstraps.
In any of these cases, the best way to use the configuration data throughout your app is to define it as a constant at the bootstrap phase: app.constant('CONFIG', configData);, assuming that configData is a variable that contains the data from your config.json file.
Then you can use dependency injection to provide CONFIG to all your controllers, services and directives.

How to compile a TypeScript project to a single JS file so it is usable in browser

I have to write a Javascript SDK for a little project I am working on. To do that, I had thought of creating a TypeScript project and compiling it to a single Javascript file, so the users of my SDK could just inject that file in their web pages.
However, I just came to know that if I use import, and try to compile to a single file, then it only supports SystemJS.
So, how to compile a TypeScript project to a single JS file so it is usable in browser?
By usable in browser, I mean that if I create a class App in TypeScript, then I could do this in dev console:
var x = new App();
I have been at this for more than a hour now, and everything I have found seems to suggest that this is not possible.
Edit: This doesn't really answer my question. Like I said in the example, I need the functionality that if there is a class called App in my TypeScript project, it should be visible to the browser with the same name, so I could do var x = new App() in my dev console. (Or a user can do this in his JS file that he injects after injecting my SDK file). That answer is just telling how to create an outfile in SystemJS.
For this you can use webpack, it is a Node.JS utility that attempts to bundle Node.JS-like modules. Webpack doesn't automatically export modules to the global object, but generates (or attempts to generate) a function that replace the Node.JS's default require, which is used to execute the entry module and others, thus you can modify this function for exporting each module (or properties of each module) in the global object.
(In TypeScript, use the CommonJS module. Second, install and use the ts-loader plugin among with webpack, so you'll directly compile TypeScript from webpack.)
Maybe that applies to Webpack 2. For example, you modify the __webpack_require__ function. It is not inside the global object and thus you must interfere in the webpack's generated source code, at function __webpack_require__:
function __webpack_require__(moduleId) {
// [...] (After the `if (installedModules...) ...`)
/*
* You don't have access to the module name, so export each
* property to the browser's global object.
*/
var exports = module.exports;
for (var key in exports)
window[key] = exports[key];
}

Webpack change window globale object scope

I am importing the npm module JSEncrypt in my module to encrypt data. JSEncrypt has window exported global object window.Base64. I am using webpack to bundle all modules. After bundling I run the code on the browser I can write on console window.Base64 to get the value of this object. For security and compatibility reasons I would like to prevent that by changing window.Base64 to local scope instead of window. Is that possible through webpack?
You can look at the various options available for shimming modules, specifically the exports-loader.
This will bind the global to a module scope and it won't be overwriteable outside of Webpack's runtime.

Angular window injecting

Is it possible prevent angular instance inject into global (window) scope when being required and bundled with webpack for example or any other module bundler?
I have found that current main javascript file in angular npm package is:
require('./angular');
module.exports = angular;
My webpack entry file contents is:
import angular from 'angular';
// my custom code goes here
So, the main webpack task is to prevent leaking variables to global scope, but if I try to log angular in Chrome DevTools like this:
console.log(angular); // => Object {version: Object, callbacks: Object}
I will see, that angular instance is injected. Any ideas to prevent this?
Additional info:
Angular.js version - 1.6.0-rc.0
Webpack version - 2.1.0-beta.27
Update.
It looks like it's hard coded into the published NPM code to assign the global Angular variable to the window object no matter what:
angular = window.angular || (window.angular = {})
So there's no direct way to prevent it from happening. You could always delete window.angular after you load it, but no promises that won't affect the library.

Categories

Resources