How can I modify a lazy loaded Webpack module path? - javascript

I have a Vue app which uses Webpack and dynamic imports:
// App.vue
<template>
<div>
<button #click="isBtnClicked = true">Load lazy component</button>
<LazyComponent v-if="isBtnClicked" />
</div>
</template>
<script>
export default {
name: 'App',
components: {
LazyComponent: () => import('./components/LazyComponent'),
},
data: () => {
return {
isBtnClicked: false,
}
}
}
</script>
// components/LazyComponent.vue
<template>
<p>Hello from lazy component</p>
</template>
When the button in the app is clicked, the Webpack runtime dynamically creates a <script> tag and appends it to the head of the document.
Is there a way to modify the src attribute of this generated <script> tag? I would like to add a dynamic query parameter to it appends the element to the DOM.
The currently generated tag looks something like:
<script charset="utf-8" src="/js/0.js"></script>
And I would like it to look like:
<script charset="utf-8" src="/js/0.js?mytoken=12345"></script>
where mytoken and 12345 are generated at runtime.
I am using webpack 4.44.0, vue 2.6.11, and vue-loader 15.9.3.

According to this and this it doesn't look like you can do this in webpack 4. I'm not entirely sure, but it looks like this pull request may allow it to be done in webpack 5.

Related

Importing external JavaScript file in VueJS

I'm using the Vue CLI and I want to import a JavaScript file that is hosted on another server. With everything I tried I get the same error as shown below.
How can I solve this problem? How can I import an external JS file?
My Vue file is shown below.
<!-- Use preprocessors via the lang attribute! e.g. <template lang="pug"> -->
<template>
<div id="app">
<p>Test</p>
<button #click="doSomething">Say hello.</button>
</div>
</template>
<script>
import TestFile from "https://.../src/TestFile.js";
export default {
data() {
return {
message: "<h1>anything</h1>"
}
},
async mounted() {
await TestFile.build();
},
methods: {
doSomething() {
alert(message);
},
},
};
</script>
<!-- Use preprocessors via the lang attribute! e.g. <style lang="scss"> -->
<style>
</style>
You cannot use import to fetch the modules from the URL, but there is a trick that you can do to use the scripts from the URL.
It's similar to attaching CDNJS's script. The solution is that you need to create the element and then append that element in the document's script.
The best solution would be, use a mounted lifecycle and then create and append it.
Example Importing FontAwesome CDN Script:
mounted() {
let fontAwesome = document.createElement('script')
fontAwesome.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/js/all.min.js')
document.head.appendChild(fontAwesome)
},
In this way registering script will give you your functions access in global object window.
For example, now I can access some of the cool properties of FontAwesome like this:
window.FontAwesome.config

How to include javascript inside template tag(or component)

What I'm trying to do
I need to use three(3) javascript libraries
[plugin1.js and plugin2.js] are plugins and depend on base.js
I'm trying to achieve this via <script> tag as shown below:
I'm doing this way because I was doing like this when I was using plain javascript.
<template>
<div class="video">
<script type="application/javascript" :src="`${publicPath}base.js`"></script>
<script type="application/javascript" :src="`${publicPath}plugin1.js`"></script>
<script type="application/javascript" :src="`${publicPath}plugin2.js`"></script>
</script>
...
</template>
What is the problem
There are undefined errors like Uncaught TypeError: blablabla_name is undefined
Libraries not loaded into same scope.
Question
How can I load these libraries into same scope?
It can be solved by adding your external script into the vue mounted() of your component
<template>
.... your HTML
</template>
<script>
export default {
data: () => ({
......data of your component
}),
mounted() {
let recaptchaScript = document.createElement('script')
recaptchaScript.setAttribute('src', 'https://www.google.com/recaptcha/api.js')
document.head.appendChild(recaptchaScript)
},
methods: {
......methods of your component
}
}
</script>

how to create html otomatic in template vue file

i want to create html inside template in vue, but i have to create manual,i using vscode editor
<template>
<div class="hello">
<h1>hellow word</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
in code above , even only create h1 i have to make open tag html dan create close, than take time
any body have solution
i have install many snippet but all is not working
Install plugin Vetur for Visual studio code and make sure your file extension is .vue

How to include local javascript on a Gatsby page?

I'm a total React newbie and I guess there is something fundamental I don't quite understand here. A default Gatsby page looks like this. Is there a way to use a local .js file somewhat like this?
<script src="../script/script.js"></script>
What I would like to achieve is to have react ignore script.js but still have the client side use it. A default Gatsby page looks like this, is it possible to do somerthing like that there?
import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"
const IndexPage = () => (
<Layout>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
After several hours of frustration I finally stumbled upon discussion on GitHub that solved this for me. In Gatsby, there is a thing called static folder, for which one use case is including a small script outside of the bundled code.
Anyone else in the same situation, try proceeding as follows:
Create a folder static to the root of your project.
Put your script script.js in the folder static.
Include the script in your react dom with react-helmet.
So in the case of the code I posted in my original question, for instance:
import React from "react"
import Helmet from "react-helmet"
import { withPrefix, Link } from "gatsby"
import Layout from "../components/layout"
import Image from "../components/image"
import SEO from "../components/seo"
const IndexPage = () => (
<Layout>
<Helmet>
<script src={withPrefix('script.js')} type="text/javascript" />
</Helmet>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
Notice the imports
import Helmet from "react-helmet"
import { withPrefix, Link } from "gatsby"
and the script element.
<Helmet>
<script src={withPrefix('script.js')} type="text/javascript" />
</Helmet>
This would have saved hours of my time, hopefully this does it for someone else.
There are many ways to add scripts in GatsbyJS...
To execute a script on a specific page
create a stateless ScriptComponent.js file and place it inside your /src folder.
in your ScriptComponent.js use require() to execute the script inside useEffect() like this:
const ScriptComponent = ({
src, // if internal,put a path relative to this component
onScriptLoad = () => {}, // cb
appendToHead = false,
timeoutDuration = 10,
defer = false,
isExternal = false,
}) => {
useEffect(() => {
setTimeout(() => {
if (isExternal) {
const script = document.createElement('script');
script.src = src;
script.onload = onScriptLoad;
defer
? script.defer = true
: script.async = true;
appendToHead
? document.head.appendChild(script)
: document.body.appendChild(script);
} else { // for internal scripts
// This runs the script
const myScript = require(src);
}
}, timeoutDuration);
}, []);
return null;
};
To run it on client-side, you could check the window object inside your script.js file if you didn't run it in useEffect:
if(typeof window !== 'undefined' && window.document) {
// Your script here...
}
finally, go to the page you want to execute the script in it (e.g. /pages/myPage.js ), and add the component <ScriptComponent />
If you want to execute a script globally in (every component/page) you could use the html.js file.
first, you'll have to extract the file (in case you didn't) by running:
cp .cache/default-html.js src/html.js
inside your html.js file:
<script dangerouslySetInnerHTML= {{ __html:`
// your script here...
// or you could also reuse the same approach as in useEffect above
`}} />
Just create gatsby-ssr.js file on root folder
and add the following pattern for your scripts folder
import React from 'react'
export const onRenderBody = ({ setPostBodyComponents }) => {
setPostBodyComponents([
<script
key="https://code.jquery.com/jquery-3.2.1.slim.min.js"
src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossOrigin="anonymous"
defer
/>,
<script
key="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossOrigin="anonymous"
defer
/>,
<script
key="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossOrigin="anonymous"
defer
/>
])
}
Then, you at the end of dom you'll see the links to scripts
If you'd like to use a Gatsby plugin, which to me is no different from using an external library like Helmet (plugins are npm packages after all), you could use gatsby-plugin-load-script.
You can provide either the url to the src attribute or a local path. If you're going to store your JS in a local file such as some-minified-js.min.js - make sure to store in the static directory at the root of your project.
Once you do this, you can access via the global object:
global.<object or func name here>
For example, I was trying to include a very small JS library via a minified file, so I stored the file in /static/my-minified-library.min.js and then:
Installed the plugin: npm i --save gatsby-plugin-load-script
Added this to my gatsby-config.js
plugins: [
{
resolve: "gatsby-plugin-load-script",
options: {
src: "/my-minified-library.min.js",
},
},
],
Accessed in my react component like so:
useEffect(() => {
const x = new global.MyImportedLibraryObject();
}, []}
Gatsby uses html.js in the src folder. Not index.html like most react projects.
Example html.js file:
import React from "react"
import PropTypes from "prop-types"
export default class HTML extends React.Component {
render() {
return (
<html {...this.props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{this.props.headComponents}
</head>
<body {...this.props.bodyAttributes}>
{this.props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: this.props.body }}
/>
{this.props.postBodyComponents}
</body>
</html>
)
}
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
}
For adding custom Javascript using dangerouslySetInnerHTML inside src/html.js:
<script
dangerouslySetInnerHTML={{
__html: `
var name = 'world';
console.log('Hello ' + name);
`,
}}
/>
You can try adding your js there but, note that your js may not work as expected. You can always look into react-helmet for more dynamic apps and adding scripts to <head>.
Gatsby Documentation: https://www.gatsbyjs.org/docs/custom-html/
You can do this very easily with the Gatsby plugin "gatsby-plugin-load-script."
Simply do this:
Create a folder named static at the root of your gatsby app
Place your script in it
Add the following configuration in gatsby-config.js
{
resolve: 'gatsby-plugin-load-script',
options: {
src: '/test-script.js', // Change to the script filename
},
},
I'm not sure if anyone still needs this answer, but here it goes:
The answer by Elliot Marques is excellent. If you need it for a local file, upload the script to Github and use a service like JSDelivr. It saves a lot of time and stress.
React works with dynamic DOM. But for rendering it by browser, your web server should send a static index page, where React will be included as another script tag.
So, take a look on your index.html page, which you can find in public folder. There you could insert your script tag in the header section, for example.

How do I pass data from Vue Instance to a Single File Component

I've been working with Vue for sometime, but I've never really tried working with Single File Components alongside webpack. Here's the problem I'm having. I have 2 files: main.js (which contains the Vue root instance) and App.vue (which is a single file component. The code in each file goes as thus:
main.js:
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
components: { App, },
data(){
return {
greeting: "Hello World!",
}
},
render: h => h(App),
});
App.vue:
<template>
<div id="app">
{{greeting}}
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
Please note that I'm using webpack, and the main.js file is meant to be an entry point. The code is bundled to a file called bundle.js.
Now, my problem is that, when the template in App.vue renders, it doesn't show "Hello Word", which is the value of {{greeting}}. I expect that data passed from the root Vue instance in main.js should be available to the App.vue component.
The {{greeting}} isn't evaluated when I put it in my index.html file, which links to bundle.js (the bundled version of main.js)
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Nothing</title>
<script src="/dist/build.js"></script>
</head>
<body>
<div id="app"></div>
{{greeting}}
</body>
</html>
Does this mean that data in the root vue instance isn't available anywhere? What should I do?
The greeting needs to be in your component's data. This has nothing to do with SFC (Single File Components), it's just the way Vue's templates work: they read from the component's data.
So what you need to do is move the data to the appropriate component, which is tied with the template where you're trying to use.
<template>
<div id="app">
{{ greeting }}
</div>
</template>
<script>
export default {
name: 'App',
data () {
return { greeting: 'Hello World!', }
},
}
</script>

Categories

Resources