I have an external library that I need to load in and be able to reference in my app. The library is not available on NPM so I can't just import it at the top of my app like I have done for my other plugins. After searching around for the best workaround for this it seems that creating a global variable in webpack is the best way to access this library however the limited documentation i've found online isn't very clear. Here's what i've done:
In my webpack.config file i've added the following line in:
new webpack.ProvidePlugin({
MarketingCloud: "../src/scripts/marketing-cloud-javascript-sdk/marketing_cloud",
}),
My understanding is that the line above would give me access to the function in this script because it is now defined as a global variable but when I try and include in one of my components onclick functions I get a MarketingCloud is not defined error message. if I change this to window.MarketingCloud it renders out the page but the onclick function gives me the sane bit defined error.
Im using the create-react-app boilerplate which uses webpack/ babel. If it helps, here are the contents of the file i'm trying to add, the import jquery at the top was added by me to remove some jquery is not defined errors:
import {$, jQuery} from 'jquery';
(function($) {
window.MarketingCloud = {
env: {},
wsse: new Wsse(),
/** Make the api request */
/* callback should follow standard jQuery request format:
* function callback(data)
*/
makeRequest: function (username, secret, method, params, endpoint, callback)
{
var headers = MarketingCloud.wsse.generateAuth(username, secret);
var url = 'https://'+endpoint+'/admin/1.4/rest/?method='+method;
$.ajax(url, {
type:'POST',
data: params,
complete: callback,
dataType: "json",
headers: {
'X-WSSE': headers['X-WSSE']
}
});
}
};
})(jQuery);
Any help is much appreciated!
Don't try to attach it to the window object - export default MarketingCloud instead. To quote the Webpack docs (emphasis mine):
Automatically loads modules. Whenever the identifier is encountered as free variable in a module, the module is loaded automatically and the identifier is filled with the exports of the loaded module (of property in order to support named exports).
Related
I try to use an external script (https://libs.crefopay.de/3.0/secure-fields.js) which is not vue based
I added the script via -tags into index.html
But when I try to intsanciate an object, like in the excample of the script publisher.
let secureFieldsClientInstance =
new SecureFieldsClient('xxxxx',
this.custNo,
this.paymentRegisteredCallback,
this.initializationCompleteCallback,
configuration)
Vue says "'SecureFieldsClient' is not defined"
If I use this.
let secureFieldsClientInstance =
new this.SecureFieldsClient('xxxxx',
this.custNo,
this.paymentRegisteredCallback,
this.initializationCompleteCallback,
configuration)
secureFieldsClientInstance.registerPayment()
Vue says: Error in v-on handler: "TypeError: this.SecureFieldsClient is not a constructor"
My Code:
methods: {
startPayment () {
this.state = null
if (!this.selected) {
this.state = false
this.msg = 'Bitte Zahlungsweise auswählen.'
} else {
localStorage.payment = this.selected
let configuration = {
url: 'https://sandbox.crefopay.de/secureFields/',
placeholders: {
}
}
let secureFieldsClientInstance =
new SecureFieldsClient('xxxxx',
this.custNo,
this.paymentRegisteredCallback,
this.initializationCompleteCallback,
configuration)
secureFieldsClientInstance.registerPayment()
// this.$router.replace({ name: 'payment' })
}
}
}
Where is my mistake?
EDIT:
Updated the hole question
Here is a minimal Vue app for the context your provided, which works:
https://codepen.io/krukid/pen/voxqPj
Without additional details it's hard to say what your specific problem is, but most probably the library gets loaded after your method executes, so window.SecureFieldsClient is expectedly not yet defined. Or, there is some runtime error that crashes your script and prevents your method from executing. There could be some other more exotic issues, but lacking a broader context I can only speculate.
To ensure your library loads before running any code from it, you should attach an onload listener to your external script:
mounted () {
let crefPayApi = document.createElement('script')
crefPayApi.onload = () => this.startPayment()
crefPayApi.setAttribute('src', 'https://libs.crefopay.de/3.0/secure-fields.js')
document.head.appendChild(crefPayApi)
},
I found the solution.
the import was never the problem.
I had just to ignore VUEs/eslints complaining about the missing "this" via // eslint-disable-next-line and it works.
So external fuctions/opbjects should be called without "this" it seems.
let secureFieldsClientInstance =
new SecureFieldsClient('xxxxx',
this.custNo,
this.paymentRegisteredCallback,
this.initializationCompleteCallback,
configuration)
You could download the script and then use the import directive to load the script via webpack. You probably have something like import Vue from 'vue'; in your project. This just imports vue from your node modules.
It's the exact same thing for other external scripts, just use a relative path. When using Vue-CLI, you can do import i18n from './i18n';, where the src folder would contain a i18n.js
If you really want to use a CDN, you can add it like you normally would and then add it to the externals: https://webpack.js.org/configuration/externals/#externals to make it accessible from within webpack
I have a JS file that I'm importing into my Electron's "main" (or background process), app.js, using require (eg: const myJS = require("./pathToMyJS/myJS");)
Contents of myJS.js:
module.exports = {
mFunc: function mFunc(param1) {
...
}
};
And I can use mFunc in app.js as myJS.mFunc(param1); & everything's great.
Then, I tried to follow the same process for the "renderer" JS. So my renderer.js now imports const myOtherJS = require("./myJS/myOtherJS"); where this other JS file follows the exact same module.exports logic as myJS.
And the root HTML (app.html) declares the renderer as <script defer src="./renderer/renderer.js"></script>.
But on launch, I get:
Uncaught TypeError: Cannot set property 'exports' of undefined
at renderer.js? [sm]:34
Searching online, I came across this answer that mentions that the AMD way could be used instead of the commonJS way. So I tried the following: (not sure whether this is syntactically correct!)
define(
["renderer"],
function rFunc(param1) {
... }
)
But that fails with:
Uncaught ReferenceError: define is not defined
So what's the correct way to have functions defined for export when using them in the renderer? What I've been doing so far is just to write the functions in their own JS files (eg: function func1() { ...}) & declaring all of these files in the app.html as <script defer src="./funcFile1.js"></script>.
Turns out, I was just exporting incorrectly. modules.export was the point of failure as modules is undefined on the renderer.
Instead, if I do the following to export individual functions:
// ./myJS/myOtherJS.js
export function rFunc() { ...}
And then import into my renderer.js like:
import { rFunc } from './myJS/myOtherJS';
rFunc();
Things work as I originally expected.
This Google Developers Primer on modules was useful in understanding the concepts.
AMD is not provided by node.js by default. It's used by Require.js and other FWs. Here is a link on how you can use it with node:
https://requirejs.org/docs/node.html
I'm currently developing a web application and am in the process of refactoring my code so it's bundled by WebPack.
In my HTML I have a button that calls the sendMessage() function when clicked,
<button type="button" class="btn btn-default" onclick="sendMessage(document.getElementById('claim').value)">Submit</button>
In the first version of my code, the sendMessage() function was defined in a .js file that I imported directly in the HTML,
<script src="my_js/newsArticleScript.js"></script>
The sendMessage() function is directly declared in the file, it's not inside any class or module but it calls other functions defined on the same file, so I don't want to separate it.
But now it's being bundled by WebPack. Here is my config file (the homepageScript.js is for another page):
const path = require('path')
module.exports = {
entry: {
homepage: './src/homepageScript.js',
newspage: './src/newsArticleScript.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/my_js')
}
}
I changed the script import on the HTML to import the bundled version.
And now, when I press the button I get the error
[Error] ReferenceError: Can't find variable: sendMessage
I've read about it, and I learned that webpack does not expose the functions globally. I have tried to export the function, but kept getting the same error.
Can anyone help me with this? Essentially what I need is to understant how to configure webpack or change the JS so it can be accessed by the HTML.
I'm new to JS so I'm pretty sure the way my app is designed is not the best, so any tips on improvements (maybe I should use modules, or there are better ways of calling JS function upon clicking a button) would be welcome as well. Thank you :)
Generally using text-based event handlers isn't a good idea. That said, you have a few options, with increasing amounts of changes.
For texual onchange handlers to work, sendMessage would have to be a global. So the quickest fix would be to change your code to do that. If for instance you have
function sendMessage(arg){}
in your code, you'd add an additional
window.sendMessage = sendMessage;
after it to expose it as a global variable.
A more modern approach would be to remove the onchange from the button and have the button labeled with an ID in the HTML, e.g. id="some-button-id".
Then in your JS code, you could do
var button = document.querySelector("#some-button-id");
button.addEventListener("change", function(){
sendMessage(document.getElementById('claim').value);
});
to add the change handler function using JS code, instead of with HTML attributes.
This is my first foray into any front-end development beyond basic jQuery stuff, and I'm using Vue.js along with some other packages with Browserify. My main 'app.js' looks like this:
window.$ = window.jQuery = require('jquery');
require('bootstrap');
var moment = require('moment');
var fullCalendar = require('./vendor/fullcalendar.min.js');
var datetimepicker = require('./vendor/bootstrap-datetimepicker.min.js');
var select2 = require('./vendor/select2.min.js');
var VueResource = require('vue-resource');
var Vue = require('vue');
require('./videos/show.js');
require('./home.js');
require('./search.js');
Vue.use(VueResource);
new Vue({
el: '#search',
data: {
message: 'Hello World!'
},
});
...
It works as expected this way, but when I try to create a new Vue instance in another file (in search.js, for instance) I can't do it. I get the 'Uncaught reference error: Vue is not defined' in my console. No problem with using the other required packages elsewhere - although I don't understand why I need to import jQuery the way I'm doing it... it won't work if I do:
var $, jQuery = require('jquery');
I'm sure this is something very basic and fundamental that I am not understanding yet but any help would be greatly appreciated!
The problem you are having is the basics of using modules. In general, a module should always export some behavior or property and then you require that module and use it. For example, say I wanted to add a hidden into to a form on some pages. I would do this:
AddSecretToken.js
module.exports = function(form) {
// code here to add the hidden input to the passed in form
}
Then somewhere else where I had a form that needed the secret input, I would require it:
MyForm.js
var addSecretToken = require('./AddSecretToken');
...
// some code that makes a form
addSecretToken(myForm);
...
Obviously, at some point you need some code that actually runs something but that would be your root module or the page where you require the root module. So maybe you have an app.js at the top and it requires what it needs and then runs app() without exporting anything. That makes sense. But the majority of modules shouldn't be doing that.
Any time you need some behavior, you should make a module and then anywhere you need the behavior, you require the module. Each module should require what it depends on -- it shouldn't depend on any global (sometimes jQuery is an exception).
This question already has answers here:
When should I use require() and when to use define()?
(5 answers)
Closed 5 years ago.
In RequireJS, what is the basic difference between using require() Vs define();
require(['a'], function(a) {
// some code
});
// A.js
define(['b','c','d','e'], function() {
//some code
});
Any use cases would be very helpful..
One core difference that annoyed me in early use was figuring out that a define might never be called.
As long as there is only one define per file, it will register that module as available under that filename. However, define modules are only loaded once a require function asks for each of them.
Define: If you need a XXX, then load these other things first, then return the result of this function.
Require: Load these other things, then run this function. (no "if")
Example: Let's say you include this JS file in your page:
// this is in company/welcomepage.js
define(['company/ui_library'],
function(uiLib) {
console.log('Welcome to {company}!');
}
);
If that's the only Javascript file, you could open your page, and there would be nothing in the console log, in spite of the script telling it to welcome the user. However, that changes if somewhere in the page, or in another script, you insert the following:
require(['company/welcomepage'], function() {
// optionally insert some other page-initialization logic here
});
Now, the page will put a welcome message in the console when it loads.
In fact, with that second one in place, there would be no need to manually include welcomepage.js as a <script> tag; it would load it from its location as soon as it sees the require, and realizes it needs it.
require and requirejs are the same.
require === requirejs // true
require is a way to load a module which has been defined. For example to load the logger module I could do:
require(["logger"], function(logger){
logger.bla("S");
});
Here i am calling require, specifying an already defined module called logger and using it by calling its bla method.
define is a way to define a module. For example to define a logger module I could do:
// logger.js
define(function(){
return {
bla: function(x){
alert(x);
}
}
});
Here i called define and defined the logger module. in this module I returned the bla function i want to expose.
Sometimes define looks very similar to exports because define can also depend and use other modules just like require can use other modules. Let me show you the same logger module, this time using a module
// logger.js
define(["popup"], function(popup){
return {
bla: function(x){
popup.show(x);
}
}
});
Here the logger module I defined, also has a dependency called popup and thus it looks like require.
I believe you always use define for your module definitions. You have several flavours to do so, you can define a module with its dependencies in an array as the first argument to define (as in the example you posted).
Or you can use the Simplified CommonJS wrapper, something like this:
define(function (require) {
var otherModule = require('otherModule');
return function () {
return otherModule.operation();
};
});
Maybe you got mixed up with the JSONP service dependency format, which uses require() to load the service, and then specify define() as the JSONP callback which will eventually define the module once the service responds.
So in the end, you use define() to define modules, and require() to load them.
define is how we declare a module, in accordance with AMD module format(there are other available module formats like CommonJS, ES2015, System.register, UMD)
whereas ..
require is a module loading construct that's available with module loaders like RequireJs, SystemJS, Node's built-in module loader. It is used when you want to use a module defined in one of the above-stated module formats.
require() and define() both used to load dependencies.There is a major difference between these two method.
Its very Simple Guys
Require(): Method is used to run immediate functionalities.
define(): Method is used to define modules for use in multiple locations(reuse).