VueJS use NPM Component in Browser using Browserify - vue.js

I have a custom component in my page, defined as:
Vue.component('payment-page', {
template: '#payment-template',
data: function () {
return {
...
}
},
components: {
DatePicker
},
});
Now, in this component, I need to use a datepicker/daterange picker, of which I found this to be most helpful. It can be installed from NPM using npm install vue2-datepicker --save. I am using browserify so as to be able to use the datepicker in the browser, inside my component above.
For browserify, inside my main.js file I have this:
let DatePicker = require('vue2-datepicker');
then I use the command browserify main.js -o bundle.js to create my bundle.js file which I then import in my HTML file.
Problem is I always get the error Uncaught ReferenceError: DatePicker is not defined. Anything I'm doing wrong?

Related

How to import js file from cdn?

How do we import js file from cdn?
I am building a custom component (a wrapper component) to view the pdf files. and for this I need to use pdf.js file from cdn and I am unable to import the file?
following does not work
import "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js";
To import the JS file from CDN and use in vue.js component, you can use mounted lifecycle and there you need to append your script into DOM.
Then it will be available into your window global variable.
Working code example:
mounted () {
let pdfJS = document.createElement('script')
pdfJS.setAttribute('src', 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js')
document.head.appendChild(pdfJS)
// for checking whether it's loaded in windows are not, I am calling the below function.
this.checkPDFJSLib()
},
methods: {
checkPDFJSLib() {
console.log(window.pdfjsLib)
}
}
You can normally include it in your index.html
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.2.228/pdf.min.js"></script>
Alternatively, you can use an npm library e.g vue-pdf
install it into your modules
npm install --save vue-pdf
and use it
import pdf from 'vue-pdf'

Runtime Error integrating a component lib that uses #vue/composition-api: 'You must use this function within the "setup()" method'

Any help with the following problem would be greatly appreciated!
Situation:
My project contains two packages:
child-component-lib
contains a single view About.vue written in composition-API-style (with vue2 helper libraries #vue/composition-api and vuex-composition-helpers)
exports a single RouteConfig
build as a lib
views/About.vue (child)
<template>
<div class="about">
<h1>This is an about page (as component lib)</h1>
</div>
</template>
<script>
import { defineComponent } from "#vue/composition-api";
import { createNamespacedHelpers } from "vuex-composition-helpers";
export default defineComponent({
components: {},
setup(_, { root }) {
const { useGetters, useActions } = createNamespacedHelpers("account"); // error thrown here!
}
});
</script>
router/index.ts (child)
export const routes: Array<RouteConfig> = [{
path: "/",
name: "About",
component: () => import(/* webpackChunkName: "about" */ "../views/About.vue")
}];
lib.ts (child)
export const routes = require("#/router").routes;
package.json (child)
"scripts": {
"build": "vue-cli-service build --target lib --name child-component-lib src/lib.ts"
...
parent-app
imports the route from child-component-lib into its router
contains a simple view that displays one line of text and a <router-view />
package.json (parent)
"dependencies": {
"#tholst/child-component-lib": "file:../child-component-lib",
router/index.ts (parent)
import { routes as childComponentRoutes } from "#tholst/child-component-lib";
const routes: Array<RouteConfig> = [...childComponentRoutes];
const router = new VueRouter({routes});
export default router;
App.vue (parent)
<template>
<div id="app">
<Home />
<router-view />
</div>
</template>
<script>
import { defineComponent } from "#vue/composition-api";
import Home from "#/views/Home.vue";
export default defineComponent({
components: {
Home
},
setup(_, { root }) {
...
}
});
</script>
Expected behavior
It works without problems.
Actual behavior
I see an error output in the console. [Vue warn]: Error in data(): "Error: You must use this function within the "setup()" method, or insert the store as first argument." The error message is misleading, because the error is actually thrown inside setup() method. It can be traced back to getCurrentInstance() returning undefined (inside #vue/composition-api).
Investigation:
It turns out that the error disappears when I include the same About.vue in the parent-app itself (just switch the route, to try it out), i.e., it works when we avoid the import from the built library.
So it looks like it's a problem with the build setup
(one of vue.config.js, webpack, babel, typescript, ...)
Reproduce the error:
1. Clone, install, run
git clone git#github.com:tholst/vue-composition-api-comp-lib.git && cd vue-composition-api-comp-lib/child-component-lib && npm install && npm run build && cd ../parent-app/ && npm install && npm run serve
or one by one
git clone git#github.com:tholst/vue-composition-api-comp-lib.git
cd vue-composition-api-comp-lib/child-component-lib
npm install
npm run build
cd ../parent-app/
npm install
npm run serve
2. Open Browser
Go to http://localhost:8080/
3. Open Dev Tools to See Error
[Vue warn]: Error in data(): "Error: You must use this function within the "setup()" method, or insert the store as first argument."
found in
---> <Anonymous>
<App> at src/App.vue
<Root>
Error Screenshot
Environment Info:
Node: 14.2.0
npm: 6.14.8
Chrome: 86.0.4240.198
npmPackages:
#vue/babel-sugar-composition-api-inject-h: 1.2.1
#vue/babel-sugar-composition-api-render-instance: 1.2.4
...
#vue/cli-overlay: 4.5.8
#vue/cli-plugin-babel: 4.5.8
#vue/cli-plugin-router: 4.5.8
#vue/cli-plugin-typescript: 4.5.8
#vue/cli-plugin-vuex:4.5.8
#vue/cli-service: 4.5.8
#vue/cli-shared-utils: 4.5.8
#vue/component-compiler-utils: 3.2.0
#vue/composition-api: 1.0.0-beta.19
#vue/preload-webpack-plugin: 1.1.2
typescript: 3.9.7
vue: 2.6.12
vue-loader: 15.9.5 (16.0.0-rc.1)
vue-router: 3.4.9
vue-template-compiler: 2.6.12
vue-template-es2015-compiler: 1.9.1
vuex: 3.5.1
vuex-composition-helpers: 1.0.21
npmGlobalPackages:
#vue/cli: 4.5.8
I finally understood what the problems were. First, there was the actual problem. Second, there was a problem in the local development setup that made solutions to the actual problem look like they were not working.
The Actual Problem + Solution
The child-component-lib was bundling their own versions of the npm packages #vue/composition-api and vuex-composition-helpers. This had the following effect: When I was running the parent-app there were actually two instances of those libraries and the vue component from the child-component-lib was accessing the wrong object that had not been properly initialized.
The solution was to prevent the bundling of those libraries in the child-component-lib, by
making them devDependencies and peerDependencies.
instructing webpack not to bundle them on npm run build.
package.json
"dependencies": {
...
},
"devDependencies": {
"#vue/composition-api": "^1.0.0-beta.19",
"vuex-composition-helpers": "^1.0.21",
...
},
"peerDependencies": {
"#vue/composition-api": "^1.0.0-beta.19",
"vuex-composition-helpers": "^1.0.21"
},
vue.config.js
configureWebpack: {
externals: {
"#vue/composition-api": "#vue/composition-api",
"vuex-composition-helpers": "vuex-composition-helpers"
},
...
}
The Tricky Problem that Made Things Difficult
I was trying to fix this problem locally, without actually publishing the package. And it seemed to work, because I was seeing the same problem locally that I also saw in the published packages.
I did local development by directly linking the parent-app and child-component-libs. I tried both
a direct folder dependency
package.json
"dependencies": {
"#tholst/child-component-lib": "file:../child-component-lib",
},
npm link
cd child-component-lib
npm link
cd ../parent-app
npm link #tholst/child-component-lib
Both approaches have the effect that they actually import (=symlink to) the child-component-lib's folder with all files and folders (instead of only the files that would be published in the npm package).
And that meant the following: Even though I had excluded the two composition-API libs from the bundle and made them dev/peer dependencies (see solution to actual problem), they were still installed and present in the child-component-lib's node_modules. And that node_modules folder was symlinked into the parent-app package. And in this way the child-component-lib still had access to their own copy of the libraries that we wanted to exclude from the build (see actual problem). And I was still seeing the error as before.
And this way my local development approach obscured the fact that the solution to the actual problem was actually working.

Webpack external library access with Vue web components

I create a web component with vue-cli.3 in order to use it in other projects with the following command:
vue-cli-service build --target lib --name helloworld ./src/components/HelloWorld.vue
The component has a dependency on lodash. I don't want to bundle lodash with the component because lodash is going to be provided by the host application, so I configure webpack in vue.config.js like below:
module.exports = {
configureWebpack: {
externals: {
lodash: 'lodash',
root: '_'
}
}
}
So this way, I successfully compile the component without lodash.
In the host application (the one that will use the component), I add the source path of the newly created and compiled component into index.html:
<script src="http://localhost:8080/helloworld.umd.js"></script>
Register the component in App.vue:
<template>
<div id="app">
<demo msg="hello from my component"></demo>
</div>
</template>
<script>
export default {
name: "app",
components: {
demo: helloworld
}
};
</script>
The helloworld component renders without problems. Every feature of the component works without problems but as soon as I call a method of lodash, I get;
Uncaught TypeError: Cannot read property 'camelCase' of undefined
which means the component cannot access the lodash library that the host application uses.
I need to find a way to use the already bundled libraries in the host application from the components.
Is there a way?
The Vue config you used should work (see GitHub demo), so maybe there's something missing in your setup. I've listed the pertinent steps to arrive at the demo:
In public/index.html of a VueCLI-generated project, import Lodash from CDN with:
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js"></script>
In the library component (src/components/HelloWorld.vue), the _ global can be used without importing lodash. For example, display a computed property that formats the msg prop with _.camelCase.
To avoid lint errors, specify _ as an ESLint global (/* global _ */).
In vue.config.js, configure Webpack to externalize lodash:
module.exports = {
configureWebpack: {
externals: {
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_' // indicates global variable
}
}
}
}
In package.json, edit the build script to be:
"build": "vue-cli-service build --target lib --name helloworld ./src/components/HelloWorld.vue",
Run npm run build, and then edit dist/demo.html to also include the <script> tag above.
Start an HTTP server in dist (e.g., python -m SimpleHTTPServer), and open dist/demo.html. Observe the effect of _.camelCase (from step 2) without console errors.
GitHub demo

How to install a Javascript library on VueJS

I need to use the Sortable plugin from jQueryUI in my VueJS project, but I don't know how to include libraries on a VueJS 2 project.
This is what I have done so far:
1) Installed jQuery and jQueryUI this way
npm install --save jquery-ui
npm install --save jquery
2) I add these lines to main.js:
window.$ = window.jQuery = require('jquery');
window.$ = $.extend(require('jquery-ui'));
3) I use like this on my component:
<div class="height">
<app-component-component></app-component-component>
</div>
....
export default {
components: {
appComponentComponent: ComponentComponent
},
...
mounted() {
$('.height').sortable();
}
}
But I get this error:
[Vue warn]: Error in mounted hook: "TypeError: $(...).sortable is not a function"
Can you please tell me what I am doing wrong in order to import and use the library?
Thanks in advance
You can put your sortable plugin code in updated() method of vue lifecycle.
updated()
{
this.$nextTick(function () {
jQuery('.height').sortable();
})
}
You have to add this in main.js
global.jQuery = require('jquery');
var $ = global.jQuery;
window.$ = $;
require('jquery-ui');
require('jquery-ui/ui/widgets/sortable');
And you can use it inside mounted as you are.

Error in console with Vue-chartJS and Webpack

I installed vue-chartjs and also added chart.js both using NPM
When I run npm start my server is started but in broswer console i get an error
TypeError: __WEBPACK_IMPORTED_MODULE_0_vue_chartjs__.Doughnut.extend is not a function
I'm not sure what this mean. I reinstalled all packages also installed this packages separete using npm install vue-chartjs
Can you show your code of your component? Webpack 3 ?
With vue-chartjs version 3 you have to create your components this way:
import {Doughnut} from 'vue-chartjs
export default {
extends: Doughnut,
mounted () {
this.renderChart(data, options)
}
}