How to use external JavaScript objects in Vue.js methods - javascript

I'm trying to get Stripe working with my Vue.js 2 application. For PCI-DSS reasons, Stripe requires that their Javascript is always loaded from js.stripe.com. I've followed the instructions in:
How to add external JS scripts to VueJS Components
How to include a CDN to VueJS CLI without NPM or Webpack?
but I get a 'Stripe' is not defined error when I try to use the library. These solutions seemed to be aimed at merely getting a <script> tag into the output HTML (e.g. for analytics), not actually consuming the functions and objects in that script.
Here's what my component Javascript looks like:
<script>
export default {
name: "PaymentPage",
mounted() {
let stripeScript = document.createElement('script');
stripeScript.setAttribute('src', 'https://js.stripe.com/v3/');
document.head.appendChild(stripeScript);
let s = Stripe('pk_test_Fooo');
console.log(s);
}
}
</script>
I also tried adding the script tag to my public/index.html file instead, but I get the same outcome. This would probably be my preferred route, since Stripe encourages developers to import their script on all pages on the site.
<!DOCTYPE html>
<html lang="en">
<head>
// ...
<script src="https://js.stripe.com/v3/"></script>
</head>
How can I pull a script from an external CDN and use it within my component's Javascript?
I'm aware of some libraries to integrate Vue.js with Stripe (e.g. matfish2/vue-stripe and jofftiquez/vue-stripe-checkout), but the former doesn't import properly for me (I'm hitting issue #24) and the latter is built against the older Stripe API and the new version is still in beta.

You aren't giving the script time to load before checking if Stripe is there. What you need is something like this:
<script>
export default {
name: "PaymentPage",
mounted() {
let stripeScript = document.createElement('script');
stripeScript.setAttribute('src', 'https://js.stripe.com/v3/');
stripeScript.onload = () => {
let s = Stripe('pk_test_Fooo');
console.log(s);
};
document.head.appendChild(stripeScript);
}
}
</script>

Thanks to yuriy636's comment, I realised that errors were only from the linter, which presumably can't statically figure out what I'm up to.
I opted to put the script into index.html, then ensured I squashed linter errors with:
// eslint-disable-next-line no-undef
let s = Stripe('pk_test_Fooo');

In my case, I still had errors calling functions of the specific script. So it was required to specify the ¨window¨ scope. Also, if you need to access any Vue element inside the ¨onload¨function, you need a new variable for the ¨this¨ instance.
<script>
export default {
name: "PaymentPage",
mounted() {
let stripeScript = document.createElement('script');
// new variable for Vue elements.
let self = this;
stripeScript.onload = () => {
// call a script function using 'window' scope.
window.Stripe('pk_test_Fooo');
// call other Vue elements
self.otherVueMethod();
};
stripeScript.setAttribute('src', 'https://js.stripe.com/v3/');
document.head.appendChild(stripeScript);
}
}
I worked with this on Vue 2.6.

Just install the npm package npm install #stripe/stripe-js and use it like a regular import
import { loadStripe } from "#stripe/stripe-js";
export default {
async mounted() {
// init stripe
const stripe = await loadStripe('your_stripe_key_here');
this.stripe = stripe; // store the stripe instance
// access the stripe instance in your methods or where you want to use them
},
}
It's working as of 6th Jan 2022.

Related

how to use raw html file in nuxt(vue)?

I want to create a page Jump to the stripe payment page use stripe-samples/firebase-subscription-payments .
so I placed it's html/css/js file(which in the "public" folder) to my nuxt app's /static.
However, since it is for static files only, so vuex and plugins could not be used. Fortunately, the tag in html reads firebase from the url, so it is possible to use firebase.
but can I put raw html/css/js files to nuxt/pages like .vue file?(I tried but couldn't..)
I know the best way is to rewrite the html/js file into vue file, but it was too difficult for me as a beginner(Also, I'm Japanese and I'm not good at English,sorry).
or can I use npm package and module in /static/files ?
I have google it for two days and couldn't resolve it.I really need help,thank you!!
here is my code:
static/public/javascript/app.js
import firebase from firebase;
/*↑ it will be error "Cannot use import statement outside a module".
but in pages/.vue files and plugins/files, it will work...
I also tried "import firebase from '~/plugins/firebase.js'"*/
const STRIPE_PUBLISHABLE_KEY = ....
static/public/index.html
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.6/firebase-functions.js"></script>
<!-- If you enabled Analytics in your project, add the Firebase SDK for Analytics -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-analytics.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.14.5/firebase-firestore.js"></script>
↑ it read firebase from url, but I want use firebase module I've installed.
Eventually I rewrote the js / html code to vue. Basically it is completed just by copying the js code to mounted(), but since I could not manipulate the nested template tag with js, I rewrote a part using v-if and v-for.
There are several solutions for this.
To load 3rd party scripts, you can use the following solution: https://stackoverflow.com/a/67535277/8816585
Depending on what you're trying to load, using Nuxt plugins can also be a solution: https://nuxtjs.org/docs/2.x/directory-structure/plugins/
Lastly, here is a solution on how to properly handle Stripe in Nuxt: https://stackoverflow.com/a/67504819/8816585
But static is not a place to put your code in. As told, this is for public stuff like favicons, some free pdf book that you want to share to your visitors or alike.
Didn't use firebase with Nuxt lately but those can still probably help figuring out how to write it in Nuxt, I hope.
you can load the html by render() in your vue-component-file
nuxt.config.js
build: {
extend(config, ctx){
config.resolve.alias['vue'] = 'vue/dist/vue.common';
}
}
in your vue-component-file
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`
});
}
}
</script>
and the page will be rendered as a component in your vue <router-view/> or <nuxt/>, but make sure there is no <script> tag in your my_html.html, put your js code inside the render() like below
<script>
import myHtml from '~/path/to/your/html/my_html.html';
export default{
render(h){
return h({
template: `<main>${myHtml}</main>`,
created(){
console.log('I have been created!')
},
mounted(){
console.log('I have been mounted!')
},
methods: {
exampleMethod(){
alert('this is an example')
}
}
});
}
}
</script>

How to add custom scripts bundle in NextJS

I have some legacy custom javascripts that I need to bundle and put them in _document.js as a link. The filename should include a hash.
What would be the best way to accomplish this?
I tried webpack configs regarding entry/output but they break NextJs build.
The problem is that we use things like window, document, etc that do crash in server side.
Ideally what is needed is to inject this into a tag, as compiled / babelified javascript code.
What I tried is
Webpack HTML Plugin plus other plugins like InlineChunk or
InlineSource plugins. They didn't work because they generate code in
an index.html that is not used by NextJS.
Using Raw Loader to get the file content. Doesn't work because it is
not babelified.
Adding a custom entry to the Webpack config, like scripts:
'path/to/my-entry.js'. Didn't work because it adds a hash name to the
file and I have no way of knowing it.
Adding a custom entry into the NextJs polyfills. I thought it made
sense, but the polyfill tag has a nomodule which prevents its code to
run on new browsers.
Another options is to add the javascript code as a string, and then using __dangerouslySetInnerHtml but the problem is that I lose linter and babel abilities there.
I tried adding it as a page, but crashes for local development and even on build
webpack.config.js
module.exports = (nextConfig = {}) =>
Object.assign({}, nextConfig, {
webpack(config, options) {
const nextJsEntries = config.entry;
config.entry = async () => {
const entries = await nextJsEntries();
entries['pages/rscripts'] = 'test/test.js';
return entries;
};
...
Then in _document.js
<script src={`${publicRuntimeConfig.ASSET_PREFIX}/_next/${this.props.buildManifest.pages['/rscripts'][2]}`} />
You can just import js file like import 'path/to/js_file' in your _app.js/app.tsx file
import "../styles/globals.css"
import "../js/test"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
This one works fine for me
I wanted to add another answer here as I came across this and I believe some things have changed in Next JS. Next now has this script component that you can use to load external scripts or dangerously set a script.
The Next.js Script component, next/script, is an extension of the HTML
element. It enables developers to set the loading priority of
third-party scripts anywhere in their application, outside next/head,
saving developer time while improving loading performance.
The cool thing is you can put them into whatever pages you want, maybe you have a script you want on a homepage, but not other pages, and Next will extract them and place them on the page based on the strategy you select. There are a few gotchas, can't load in the head, beforeInteractive is a little finicky, so I would read the link above and the actual API reference before making any choices.
import { useEffect } from 'react';
import Script from 'next/script';
function thirdPartyScript() {
useEffect(() => {
// just for fun. This actually fires
// before the onLoad callback
}, []);
return (
<Script
id="test-script"
strategy="afterInteractive"
src="/public/pages/scripts/test.js"
onLoad={() => {
console.log('Onload fires as you would expect');
}}
/>
);
}

How to use an external non vue script in vue

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

Vue.js Tracking.js

I'm trying to make use of the tracking.js library in my vueJS application.
I've installed the package like so.
npm install --save tracking
I'm then defining the library in my main.js file
import tracking from 'tracking'
Object.defineProperty(Vue.prototype, '$tracking', { value: tracking });
Then in my component i'm trying to use the library like so
mounted() {
var tracker = new this.$tracking.ObjectTracker('webcam');
}
I feel I am calling the library wrong but the error message is
TypeError: this.$tracking.ObjectTracker is not a constructor
The problem is in the import statement, it seems that trackingjs does not support ES6 import. You have to have it in a sort of global scope
Object.defineProperty(Vue.prototype, '$tracking', { value: tracking });
new Vue({
created: function() {
var tracker = new this.$tracking.Tracker()
console.log(tracker)
}
})
Here JSFiddle example work as expected. Notice it's added only like a dependecy. i.e <script src="path/to/trackingjs">

Importing javascript file for use within vue component

I am working on a project that requires using a js plugin. Now that we're using vue and we have a component to handle the plugin based logic, I need to import the js plugin file within the vue component in order to initialize the plugin.
Previously, this was handled within the markup as follows:
<script src="//api.myplugincom/widget/mykey.js
"></script>
This is what I tried, but I am getting a compile time error:
MyComponent.vue
import Vue from 'vue';
import * from '//api.myplugincom/widget/mykey.js';
export default {
data: {
My question is, what is the proper way to import this javascript file so I can use it within my vue component?
...
Include an external JavaScript file
Try including your (external) JavaScript into the mounted hook of your Vue component.
<script>
export default {
mounted() {
const plugin = document.createElement("script");
plugin.setAttribute(
"src",
"//api.myplugincom/widget/mykey.js"
);
plugin.async = true;
document.head.appendChild(plugin);
}
};
</script>
Reference: How to include a tag on a Vue component
Import a local JavaScript file
In the case that you would like to import a local JavaScript in your Vue component, you can import it this way:
MyComponent.vue
<script>
import * as mykey from '../assets/js/mykey.js'
export default {
data() {
return {
message: `Hello ${mykey.MY_CONST}!` // Hello Vue.js!
}
}
}
</script>
Suppose your project structure looks like:
src
- assets
- js
- mykey.js
- components
MyComponent.vue
And you can export variables or functions in mykey.js:
export let myVariable = {};
export const MY_CONST = 'Vue.js';
export function myFoo(a, b) {
return a + b;
}
Note: checked with Vue.js version 2.6.10
try to download this script
import * from '{path}/mykey.js'.
or import script
<script src="//api.myplugincom/widget/mykey.js"></script>
in <head>, use global variable in your component.
For scripts you bring in the browser way (i.e., with tags), they generally make some variable available globally.
For these, you don't have to import anything. They'll just be available.
If you are using something like Webstorm (or any of the related JetBrains IDEs), you can add /* global globalValueHere */ to let it know that "hey, this isn't defined in my file, but it exists." It isn't required, but it'll make the "undefined" squiggly lines go away.
For example:
/* global Vue */
is what I use when I am pulling Vue down from a CDN (instead of using it directly).
Beyond that, you just use it as you normally would.
I wanted to embed a script on my component and tried everything mentioned above, but the script contains document.write. Then I found a short article on Medium about using postscribe which was an easy fix and resolved the matter.
npm i postscribe --save
Then I was able to go from there. I disabled the useless escape from eslint and used #gist as the template's single root element id:
import postscribe from 'postscribe';
export default {
name: "MyTemplate",
mounted: function() {
postscribe(
"#gist",
/* eslint-disable-next-line */
`<script src='...'><\/script>`
);
},
The article is here for reference:
https://medium.com/#gaute.meek/how-to-add-a-script-tag-in-a-vue-component-34f57b2fe9bd
For anyone including an external JS file and having trouble accessing the jQuery prototype method(s) inside of the loaded script.
Sample projects I saw in vanilla JS, React and Angular were simply using:
$("#someId").somePlugin(options)
or
window.$("#someId").somePlugin(options)
But when I try either of those in my VueJS component I receive:
Error: _webpack_provided_window_dot$(...).somePluginis not a function
I examined the window object after the resources had loaded I was able to find the jQuery prototype method in the window.self read-only property that returns the window itself:
window.self.$("#someId").somePlugin(options)
Many examples show how to load the external JS file in VueJS but not actually using the jQuery prototype methods within the component.

Categories

Resources