Vue and Rollup: how to bundle a collection of components? - javascript

I want to bundle a couple of components that I wrote in Vue. To do
so I am using Rollup with an index.js file (the file which I call Rollup on) that looks like this:
import ComponentA from './components/ComponentA'
import ComponentB from './components/ComponentB'
var myMod = {
ComponentA: ComponentA,
ComponentB: ComponentB
}
window.myMod = myMod
that then gets bundled into main.js.
I can include my module now in an HTML page with a normal <script src="main.js"> tag.
From here I can now defined components that use my modules components e.g.
ComponentA = myMod.ComponentA
app = new Vue({
el: '#app',
components: { ComponentA },
// components: myMod, also works if I want to use all the components
template: ` ...<ComponentA/>...`
})
and, until recently, this was fine for me.
I was wondering I could now use my module of components in a single file vue component outside of my module (e.g. if I want to make a site with vue-cli-3).
e.g.
<template>...</template>
<script>
import myMod from 'main.js'
ComponentA = myMod.ComponentA
export default {
name: 'SFCInAnotherApp',
components: { ComponentA },
}
</script>
<style>...</style>
I have tried changing my index.js file to:
export default myMod
rather than window.myMod
however, now when I import my component, the module is undefined..
e.g.
<template>...</template>
<script>
import myMod from 'main.js'
console.log(myMod)
ComponentA = myMod.ComponentA
export default {
name: 'SFCInAnotherApp',
components: { ComponentA },
}
</script>
<style>...</style>
----> undefined
if I keep the window.myMod = myMod line, once the page renders (with errors from the apps trying to use myMod components), I can of course access myMod with no issue.
How do I use rollup to create a collection of components that I can then, from other vue projects, import via either:
import {componentA} from '<path-to-myMod>'
or
import myMod from '<file-with-my-mod>'
var ComponentA = myMod.ComponentA
In short:
Using Rollup, how should I in my index.js file import my Vue components and export my module so that I can use it as I currently do as well as import it into single file components?

Related

Finding named functions in built Vue app files

I have a completed Vue app that I am trying to 'build' and then trying to use in another app as an import.
In main.js
export function appInit(options = {}){
new Vue({
render: h => h(App),
store,
router
}).$mount('#app')
}
I also tried
export default function appInit(....)
I then build the project using a vue.config.js file using this command.
vue-cli-service build --target lib --name myApp
This generates a /dist folder with
myApp.common.js
myApp.common.js.map
myApp.umd.js
myApp.umd.js.map
myApp.umd.min.js
myApp.umd.min.js.map
I have tried the common.js file and the umd.min.js file in another app and imported them like this.
import MyApp from './js/myApp.common.js'
//or
import MyApp from './js/myApp.umd.min.js'
//or
import MyApp from './js/myApp.common'
//or
import MyApp from './js/myApp.umd.min'
Then underneath I call.
MyApp.appInit()
I even tried
MyApp()
In every case, this is the error..
"export 'appInit' was not found in './js/myApp.common.js'
or in any other of the files I tried.
Furthermore, I searched myApp.common.js and myApp.umd.min.js looking for the string 'appInit'. After all, that IS the function name I need to call. It does not exist in either file. Of course.
Is that the problem, that named exports do not work on obfuscated files? What am I missing here?
I have even tried this..
I created var with just the Vue object
var MyApp = new Vue({
render: h => h(App),
store,
router
})
Then an export function that returns it
export function appInit(){
return MyApp
}
In my test app I am importing the common.js build file with:
import appInit from './js/myApp.common'
Then I did
appInit.$mount('#app')
appInit should be the function I exported.
export 'default' (imported as 'appInit') was not found in './js/myApp.comm
on'

How to import a js class in main.js file of a vue.js project and use it in all the components instead of importing in each component?

I have written some JS classes that I would like to import in the app.js/main.js file of my vue.js project so that I can instantiate them in the components. Right now I am having to import the same JS class in all the components where I need the class individually.
I've tried the import in the main.js file but the components don't recognize it.
in the main.js file, I am importing like as follows
import Permissions from './Permissions'
However, when I want to instantiate the Permissions class in my component like
data() {
permissions: new Permission({
some object properties...
})
}
the component doesn't know what Permissions is.
How do I let the component know what Permissions class is?
To do it in the vue way, you can create your own plugin or mixin. See detailed instructions here
So, you can create a permissions plugin in permissions-plugin.js
import Permissions from './Permissions'
const PermissionsPlugin = {
install(Vue, options) {
// This adds the $getPermissions method to all instances
Vue.prototype.$getPermissions = function(properties) {
return new Permission({
some object properties...
})
}
}
};
Then you have to tell vue to use your plugin:
import Vue from 'vue'
import PermissionsPlugin from './permissions-plugin.js'
import App from './App.vue'
// The plugin is loaded here.
Vue.use(PermissionsPlugin)
new Vue({
el: '#app',
render: h => h(App)
});
And lastly now from any component you should be able to use your function like:
this.$getPermissions(properties)

Organizing React Components

I am building a React App which consists of lot of smaller components. At present I am importing the components in app.js like this:
import Nav from './components/nav'
import ColorPicker from './components/colorPicker'
class App extends Component {
render() {
return (
<div>
<Nav />
<ColorPicker />
</div>
);
}
}
export default App;
Each component is a separate js file (nav.js, colorPicker.js). Is there anyway to just import everything in components folder so I don't have to explicitly specify importing of the components.
I'm not sure if there is a way to just import everything from a folder with one module per file, but you can make a kind of index.js file in which you would import everything that you will want, then:
export * from nav;
export * from colorPicker;
And then you only have to import your one index file from which you can: import {nav, colorPicker} from './components/things';
You always have to explicitly set the import of the components you use, but what you can do is decrease the amount of code typed by setting up an index file where you export all components you want to make available in said file, like this for example:
./components/index.js
import Component1 from './Component1';
import Component2 from './Component2';
import Component3 from './Component3';
export {
Component1,
Component2,
Component3,
};
Then import the needed components in the desired file like this:
./app.js
import { Component1, Component2 } from './components';
class App extends Component {
render() {
return (
<div>
<Nav />
<ColorPicker />
</div>
);
}
}
export default App;
Tree structure
app.js
components
+---
Component1.js
Component2.js
index.js
If you can add a babel plugin, you can use babel-plugin-wildcard, that is a plugin that makes exactly what you want.
Taken from NPM:
With the following folder structure:
|- index.js
|- dir
|- a.js
|- b.js
|- c.js
the following JS:
import * as Items from './dir';
will be compiled to:
const Items = {};
import _wcImport from "./dir/a";
Items.A = _wcImport;
import _wcImport1 from "./dir/b";
Items.B = _wcImport1;
import _wcImport2 from "./dir/c";
Items.C = _wcImport2;
meaning you will be able to access the items using Items.A and Items.B.
You can also selectively choose files using:
import { A, C } from "dir/*";
which in the above example would convert to:
import A from "./dir/a";
import C from "./dir/c";
The above is like doing:
import * as temp from "dir";
const { A, C } = temp;
Answer found inside this post.

Using mixins with Vuejs

I'm currently learning how to develop an app with Vuejs. I have a main.js file with the code for setting up Vue.js. I created a new directory /mixins with a new file api.js. I want to use that as mixin so that every component can use a function to access my api. But I don't know how to do it.
This is my /mixins/api.js file:
export default{
callapi() {
alert('code to call an api');
},
};
This is my main.js file:
import Vue from 'vue';
import VueRouter from 'vue-router';
import VueResource from 'vue-resource';
import { configRouter } from './routeconfig';
import CallAPI from './mixins/api.js';
// Register to vue
Vue.use(VueResource);
Vue.use(VueRouter);
// Create Router
const router = new VueRouter({
history: true,
saveScrollPosition: true,
});
// Configure router
configRouter(router);
// Go!
const App = Vue.extend(
require('./components/app.vue')
);
router.start(App, '#app');
How can I include my mixin the right way now, so that every component has access to the callapi() function?
If you want to use a mixin on a specific component, rather than all components, you can do it like this:
mixin.js
export default {
methods: {
myMethod() { .. }
}
}
component.vue
import mixin from 'mixin';
export default {
mixins: [ mixin ]
}
Another thing you might consider is using a component extension design pattern i.e. creating a base component and then inheriting from that in sub components. It's a little more involved but keeps code DRY if you have many components sharing many options and perhaps inheriting the template too.
I've written about it on my blog if you're interested.
You can apply mixin globally using Vue.mixin
api.js
------
export default {
methods: {
callapi() {};
}
}
main.js
-------
import CallAPI from './mixins/api.js';
Vue.mixin(CallAPI)
As the documentation states you should use it carefully:
Use global mixins sparsely and carefully, because it affects every single Vue instance created, including third party components.

How to register global components with vue-router

I'm using Vue.js with the vue-cli. I chose for the webpack setup.
I wired up the main.js file for routing, though I can't find a way to globally register my components.
main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App'
import Companies from './components/pages/Companies'
import Income from './components/pages/Income'
import Login from './components/pages/Login'
Vue.use(VueRouter)
let router = new VueRouter()
router.map({
'/companies': {
component: Companies
},
'/income': {
component: Income
},
'login': {
component: Login
}
})
router.start(App, 'body')
App.vue
<template>
<div>
<router-view></router-view>
</div>
</template>
<script>
import {Auth} from './lib/api'
import Loader from './components/Loader'
export default {
components: {
Loader
},
ready () {
Auth.isLoggedIn().then(
(response) => {
if (response.data === false) {
this.$router.go('/login')
} else {
this.$router.go('/companies')
}
},
(response) => {
this.$router.go('/login')
}
)
}
}
</script>
When I use my Loader component in some view, I get the following warning.
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I provided the name in the component and it didn't make any difference. I'm using the loader-component in the login-view.
I found out that I should either define the component in the component that I'm going to use it or globally. Though, I can't find out how to define it globally with the routing.
The way you have it set up now, The loader component is only locally available in the template of the App component.
Routing has no influence on global component registration, just do it like without a router:
// main.js, before all the router stuff:
import Loader from './components/Loader'
Vue.component('loader', Loader)
or register it locally in your Login component. As you already did it in App.vue, you know what to do with Loader.vue

Categories

Resources