ReactJS - How to set property on window? - javascript

I've encountered an unfamiliar scenario. In my React project, I imported a 3rd party vendor api file. However, the vendor api makes internal calls using the Q promise library, which is not included. The api expects window.Q to be set and is a direct dependency of the api. I can't seem to figure out how to set this on window properly so that when I import the vendor file at the top of my source file and use it, it doesn't throw this error:
TypeError: undefined is not an object (evaluating '$q.defer')
global-variables.js:
Note: I imported the vendor library in this file because ds is a global variable created in the file for the consumer to make calls with.
import '../../vendor/vendor-library';
const globals = {
DATA_SERVICE: ds,
};
export default globals;
user.js:
import globals from '../globals/global-variables';
const userApi = {
getCurrentUser() {
return globals.DATA_SERVICE.getDataForCurrentObject('User', 'ID');
},
};
export default userApi;
I tried doing this at the top of my project entry point but it didn't solve the problem:
index.js:
import q from 'q';
window.Q = q;
Any help would be greatly appreciated.

I would recommend using an extension provided by either webpack or whatever other bundler you are using to bundle your javascript to provide Q as a global.
In webpack this can be done with the webpack.ProvidePlugin
Example:
module.exports = {
module : {
...
},
plugins : [
new webpack.ProvidePlugin({
Q: "q",
"window.Q": "q",
}),
],
};
In this case "q" is the name of the Q library from npm, which you would have to add as a dependency to your project.

Related

Cannot use newly installed plugins (node modules) in Nuxt pages/components

First off, I'm a beginner with NuxtJS and front-end development in general, so it might be that I'm missing something - though I do believe I went through all the options before posting here. Apologies in advance if that is not the case.
I've been having trouble using installed modules that I've registered as plugins. For example, take mapbox-sdk.
After installing it with npm install #mapbox/mapbox-sdk, which correctly creates #mapbox/mapbox-sdk in node_modules, I register it in nuxt.config.js:
plugins: [
...
"~/plugins/mapbox-sdk.js",
],
Of course, I also create the mapbox-sdk.js file in plugins/, containing:
import "#mapbox/mapbox-sdk";
Then, in a page (say, myMap.vue), when I try:
var mapboxClient = mapboxSdk({ accessToken: MY_ACCESS_TOKEN });
which is the basic usage example in the documentation, I get:
mapboxSdk is not defined
in the console. This behavior extends to every single module I installed today, but is not the case for modules I had previously installed.
The reason why you're getting the error mapboxSdk is not defined is because there are a few issues with the way you've set up this plugin.
Docs here https://nuxtjs.org/docs/2.x/directory-structure/plugins/, they have some useful diagrams.
There are a couple of ways you can use this package.
Plugin
// ~/plugins/mapbox-sdk.js
import mapboxSdk from '#mapbox/mapbox-sdk'
export default (_ctx, inject) => {
// Exposing the mapboxSdk to your Nuxt app as $mapBox.
inject('mapBox', mapboxSdk)
}
Then in nuxt.config.js, same as you've already done.
plugins: [
...
"~/plugins/mapbox-sdk.js",
],
Then in your component myMap.vue
var mapboxClient = this.$mapBox({ accessToken: MY_ACCESS_TOKEN });
Directly in the component:
If you don't wish to use a plugin, the way that #kissu mentioned above https://stackoverflow.com/a/67421094/12205549 will also work.
Try adding this after the import to let Vue know that this method exists (in the same .vue file) at first
<script>
import mapboxSdk from '#mapbox/mapbox-sdk'
export default {
methods: {
mapboxSdk,
},
mounted() {
console.log('mapbox function >>', mapboxSdk)
},
}
</script>
Do you have it working in a .vue component at first ?

How do I manually include "#material/drawer" into my component?

I am trying to manually include the #material/drawer npm package into my Ember app. I tried following this guide but I'm running into some weird errors in my Chrome dev console:
Uncaught SyntaxError: Unexpected token *
Uncaught ReferenceError: define is not defined
The first is from the imported node_modules/#material/drawer/index.js file and the second is from my generated shim.
My component code:
import Component from '#ember/component';
import { MDCTemporaryDrawer, MDCTemporaryDrawerFoundation, util } from '#material/drawer';
export default Component.extend({
init() {
this._super(...arguments);
const drawer = new MDCTemporaryDrawer(document.querySelector('.mdc-drawer--temporary'));
document.querySelector('.menu').addEventListener('click', () => drawer.open = true);
}
});
In my ember-cli-build.js:
app.import('node_modules/#material/drawer/index.js');
app.import('vendor/shims/#material/drawer.js');
My generated shim:
(function() {
function vendorModule() {
'use strict';
return {
'default': self['#material/drawer'],
__esModule: true,
};
}
define('#material/drawer', [], vendorModule);
})();
What exactly am I doing wrong? It almost seems as though raw ES6 code got imported rather than compiled into my JS build output.
I also read this SO post but there are too many answers and I'm not sure which to do. It seems this specific answer is what I'm trying to do but not verbatim enough.
Creating a shim only ensures that ember-cli gets an AMD module, which you then can import in your app files.
If the npm package needs a build or transpiling step beforhand, this won't work.
You need a way to get the package build within the ember-cli build pipeline.
Luckily there are addons which can take care of this for you: ember-auto-import and ember-cli-cjs-transform.
You may have also heard of ember-browserify, which does the same thing, but it's deprectaed in favor of ember-auto-import.
I'd suggest you try ember-auto-import:
ember install ember-auto-import
You then should be able to import as you tried:
import { MDCTemporaryDrawer, MDCTemporaryDrawerFoundation, util } from '#material/drawer';
No shim or app.import needed, as ember-auto-import will take care of this for you.

How can I use a config file in React?

Let's say I have 5 jsx files and each file uses some config parameter.
My index.js file imports all of these 5 jsx files.
Instead of having my config data spread accross 5 files, is there a way for my jsx files to get the data from a global JS object which has loaded the data from a config file?
I've seen some examples, but I've not been able to get them to work.
JS6 import function | Example using webpack
Assuming ES6:
config.js
export const myConfig = { importantData: '', apiUrl: '', ... };
Then:
jsxFileOne.js, jsxFileTwo.js, ...
import { myConfig } from 'config.js';
There are other ways to import & export things globally leveraging webpack, but this should get you started.
If your project is built using Webpack, consider using node-env-file.
Example config file snippets:
development.env
API_SERVER_URL=https://www.your-server.com
webpack.config.js
const envFile = require('node-env-file');
...
const appSettingsFile = isDevBuild ? '/settings/development.env' : '/settings/production.env';
try {
envFile(path.join(__dirname + appSettingsFile));
} catch (error) {
console.log("Failed to read env file!: " + __dirname + appSettingsFile);
}
...
plugins: [
new webpack.DefinePlugin({
"process.env": {
API_SERVER_URL: JSON.stringify(process.env.API_SERVER_URL)
}
})
...
]
Inside your js/jsx code, you can now access process.env.API_SERVER_URL variable which will contain the required value.
It seems dotenv package is more popular, you can try this out as well.
Very old problem, that nobody took the time to solve, until now. I leave this for future readers because this is a top search result for configuration in React.
I created wj-config to deal exactly with this. Be sure to pay close attention to the React notes as you will need to enable top-level awaits in webpack, either by ejecting or using the #craco/craco NPM package.
You may also read this blog post that explains its use.

Typescript compiler error when importing json file

So the code is simple:
calls.json
{"SERVER":{
"requests":{
"one":"1"
}
} }
file.ts
import json = require('../static/calls.json');
console.log(json.SERVER);
the generated javascript is correct and when running the node js server, the console log json.SERVER prints '{ requests: { one: '1' } }', as it should.
The typescript compiler (commonjs) however, somehow does not particularly like this situation and throws: "Cannot find module '../static/calls.json'".
Ofcourse I tried writing a .d.ts file, like this:
declare module '../static/calls.json'{
var exp:any;
export = exp;
}
this then obviously throws: "Ambient module declaration cannot specify relative module name".
I also tried different variants, like:
declare module 'calls.json' {
import * as json from '/private/static/calls.json';
export = json;
}
and then requiring:
import json = require('calls.json');
None work properly and have their own little compiler errors :)
I want to use an external .json file because I use commonjs serverside and amd clientside and I want a single file for loading constants.
Use var instead of import.
var json = require('./calls.json');
You're loading a JSON file, not a module, so import shouldn't be used is this case. When var is used, require() is treated like a normal function again.
If you're using a Node.js definition, everything should just work, otherwise require will need to be defined.
TS 2.9 added support for well typed json imports. Just add:
{
"compilerOptions": {
"resolveJsonModule": true
}
}
in your tsconfig.json or jsconfig.json. Now imports such as:
import json = require('../static/calls.json');
and
import * as json from '../static/calls.json';
should be resolved and have proper typings too!
Another solution is to change data.json to data.ts and export like this
export default {
"key" : {
...
}
}
and import as you would expect:
import { default as data } from './data'
This can also be done by using import statement if using webpack v2 which is already packed with json-loader.
Note that this is not async
import data from './data.json';//Note that this is not async
Also, in your typings.d.ts file add the following wildcard module to avoid typescript error saying: Cannot find module
declare module "*.json" {
const value: any;
export default value;
}
For anyone interested in async imports, check this article by 2uality
As of Typescript 2.9 you can import JSON file natively without any additional hack/loader needed.
The following excerpt is copied from said link above.
...TypeScript is now able to import JSON files as input files when using the node strategy for moduleResolution. This means you can use json files as part of their project, and they’ll be well-typed!
./src/settings.json
{
"dry": false,
"debug":
./src/foo.ts
import settings from "./settings.json";
settings.debug === true; // Okay
settings.dry === 2; // Error! Can't compare a `boolean` and `number`
For Angular 6 it can work with simple HTTP get call as below
Service
//interface, could be Array , object
export interface ResultJSON{
}
//Read JSON file for 3DWide
getJSON() {
return this.http.get(this.filepathUrl);
}
Component :import both service and interface and use as below
resultJSON :ResultJSON;
this
.testService
.getJSON()
.subscribe((data: ResultJSON) => {
this.resultJSON= data;
console.log(this.resultJSON);
});

TypeScript: Handling import from external libraries

I just started using Famo.us and wanted to use it as an opportunity to learn typescript at the same time to leverage on its awesomeness. So I did the following
Used yo famous to create the Famo.us project as per the documentation
I was not sure how to include typescript so I created a typeScriptHTML project, copies the .csproj file over and manually edited it. I tried using the NVTS and specified that it should create it from an existing folder but I always got an error saying that the file path was too long. It checked and some of the modules have very long path. Couldn't even delete them and the system was saying the same thing. In the end I discarded the idea and used the typescript html application. It generated no errors.
I added a file app.ts, wrote some sample code in it and it generated the js file as expected.
Now I wanted to translate main.js to main.ts and I'm stuck with the following issues
i. var Engine = require('famous/core/Engine'); gives the error could not find symbol 'require'.
ii. import Engine = require('famous/core/Engine') gives the error: Unable to resolve external module "famous/core/Engine". Changing the path to "../lib/famous/core/Engine" gives a similar error with a different file name.
iii. Created a file Famous.d.ts but I don't think I'm getting it I'm not doing something right
declare module "famous/core/Engine" {
class Engine{
public createContext(): Engine
}
export = Engine
}
In the end, my confusion is how to I translate the sample code to typescript:
/*globals define*/
define(function(require, exports, module) {
'use strict';
///first
var Engine = require('famous/core/Engine');
var DeviceView = require('./DeviceView');
var mainContext = Engine.createContext();
var device;
createDevice();
function createDevice() {
var deviceOptions = {
type: 'iphone',
height: window.innerHeight - 100
};
device = new DeviceView(deviceOptions);
mainContext.add(device);
}
});
Any assistance appreciated.
It turned out to be a lot easier than I thought. One way was to declare the class and export it as a module
declare class Engine{
...
}
export module 'famous/core/Engine'{ export = Engine; }
Manage to get a tiny definition of famous running using this.

Categories

Resources