We currently have a Vue 2 component library we are using in HTML pages without a Vue app. I am wanting to migrate it to Vue 3 as it is built using Vue 2.5 and an old webpack version, but am unable to find a way to use a Vue 3 component library the same way.
The current Vue 2 entry file is like:
import Vue from 'vue';
import Test from '../src/components/Test.vue';
Vue.component('test-component', Test);
new Vue({
el: '#body'
});
An an example HTML file is
<html>
<head>
</head>
<body>
<div id="body">
<div>This is in the HTML</div>
<test-component></test-component>
</div>
<script src="dist/bundle.js"></script>
</body>
</html>
When opened in the browser, Vue replaces the html elements (e.g. <test-component>) with the Vue component.
The resulting HTML in the devtools is:
<html><head>
</head>
<body>
<div id="body"><div>This is in the HTML</div> <div>Hello from the Vue component!</div></div>
<script src="dist/bundle.js"></script>
</body></html>
Having looked at the migration docs (https://v3-migration.vuejs.org/breaking-changes/mount-changes.html etc), I tried making the equivalent entry file for Vue 3:
import { createApp } from 'vue';
import Test from '../src/components/Test.vue';
const app = createApp();
app.component('test-component', Test);
app.mount('#body');
Which I am then compiling as a library bundle using Vite
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import analyze from 'rollup-plugin-analyzer';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'#': fileURLToPath(new URL('./src', import.meta.url))
}
},
define: {
'process.env.NODE_ENV': '"production"'
},
build: {
rollupOptions: {
plugins: [analyze()]
},
lib: {
entry: [
'./lib/bundle.js'
],
name: 'MagicComponents',
fileName: (format, entryName) => entryName + '.' + format + '.js'
}
}
})
But the instead of just replacing the html elements is it replacing all the innerHTML of the #body element, resulting in
<html><head>
</head>
<body>
<div id="body"></div>
<script src="dist/bundle.js"></script>
</body></html>
Is there a way to get Vue 3 to act the same way as Vue 2 (without exporting the Vue 3 components as web components)?
Related
I've read related sections of the book Full-Stack Vue.js 2 and Laravel 5 and browsed some questions (e.g. vuejs application with different layouts (e.g. login layout, page layout, signup etc.)) to solve this issue. But none of them helped me.
I've created a Laravel + Vue SPA which works great. But when I want to create an administrator dashboard for this SPA with different JavaScript and CSS resources (as the dashboard should have completely different styles), I've confused too much. I don't know and understand what kind of an algorithm I should follow to do this.
You can see the general view of the software below,
// app.js
require('./bootstrap');
import Vue from 'vue'
import App from './views/App'
import router from './router'
import store from './store'
// Layouts
import Default from './views/layouts/Default.vue'
import Dashboard from './views/layouts/Dashboard.vue'
Vue.component('default-layout', Default);
Vue.component('dashboard-layout', Dashboard);
Vue.config.productionTip = false
export default window.vue = new Vue({
el: 'app',
components: {
App
},
router,
store
});
// App.vue
<template>
<div>
<component :is="layout">
<router-view/>
</component>
</div>
</template>
<script>
import $ from 'jquery';
window.$ = window.jQuery = $;
const default_layout = 'default';
export default {
name: 'App',
computed: {
layout() {
return (this.$route.meta.layout || default_layout) + '-layout';
}
},
};
</script>
// Default Layout
<template>
<div>
<default-navigation :is-absolute="isAbsolute" />
<slot/>
<default-footer />
</div>
</template>
<script>
import DefaultNavigation from '../components/DefaultNavigation.vue';
import DefaultFooter from '../components/DefaultFooter.vue';
export default {
name: 'Default',
components: {
DefaultNavigation,
DefaultFooter,
},
computed: {
isAbsolute() {
if (this.$route.name == 'home') {
return true;
}
}
},
};
</script>
// Dashboard Layout
<template>
<div>
<!-- Nothing here yet. -->
</div>
</template>
<script>
import DHeader from '../components/Dashboard/Header.vue';
import DSidebar from '../components/Dashboard/Sidebar.vue';
import DTitle from '../components/Dashboard/Title.vue';
export default {
name: 'Dashboard',
components: {
DHeader,
DSidebar,
DTitle
},
};
</script>
// webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
mix.js('resources/js/dashboard.js', 'public/js')
.sass('resources/sass/dashboard.scss', 'public/css');
What should I do to use a totally different style file and an extra JavaScript file in the dashboard layout?
If you're looking for separate Vue instances for both, then you can follow this
Create separate blade templates for both the instances. Add separate routes for both templates.
Route::get('/dashboard/{any?}', function () {
return view('dashboard');
})->where('any', '[\/\w\.-]*');
Route::get('/{any?}', function () {
return view('index');
})->where('any', '[\/\w\.-]*');
Create two Vue instances in separate js files, say app.js and dashboard.js. You can create this in another directory like dashboard/dashboard.js
Update your webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
.sass('resources/sass/app.scss', 'public/css');
mix.js('resources/dashboard/dashboard.js', 'public/js')
.sass('resources/sass/dashboard.scss', 'public/css');
You can link the build files in public to the corresponding blade templates.
In dev mode everything works fine but after building with static it's just blank page! I've seen a lot of issues but no one is similar to mine.
router/index.js:
import Vue from 'vue'
import Router from 'vue-router'
import Main from '#/components/Main'
import BrandPage from '#/components/BrandPage'
import Article from '#/components/Article'
Vue.use(Router)
console.log("Router");
export default new Router({
mode: 'history',
routes: [
{
path: '/',
component: Main,
props: dynamicPropsMain
}
...
]
})
main.js:
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false;
console.log("main");
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue:
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
mounted() {
console.log("App");
}
}
</script>
<style>
</style>
Also I'm logging every component this way:
mounted() {
console.log("Main");
}
And this is what I see in console when I open the index.html file from dist folder:
There's no an error btw!
I changed all paths to relative in index.html as you can see:
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<meta name=viewport content="width=device-width,initial-scale=1">
<title>cosmetic</title>
<link href=./static/css/app.6e402e4fa684582f062c00087423d24c.css rel=stylesheet>
</head>
<body>
<script src=https://use.fontawesome.com/5c25b8d8cc.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js></script>
<script src=https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.js></script>
<div id=app></div>
<script type=text/javascript src=./static/js/manifest.2ae2e69a05c33dfc65f8.js></script>
<script type=text/javascript src=./static/js/vendor.5f799c4e5a271a20f280.js></script>
<script type=text/javascript src=./static/js/app.3990053e5416194b5d89.js></script>
</body>
</html>
These all make me to think that the problem with router and I don't know how to check deeper...
Please anyone help me with that!!! I'll be very grateful!
Are you just trying to open the index.html? This will not work.
In order to use your Vue application, you have to serve the entire dist folder over a Web server.
I am using Vue.js and I want to try to render components but it isn't working
main.js:
import Vue from 'vue';
import 'bulma';
import Navbar from './Navbar.vue';
Vue.component('navbar', Navbar);
const MyC = Vue.component('myc', {
template: '<h1>Are you working?</h1>',
});
const root = new Vue({
el: '#app',
components: {
Navbar, MyC,
},
});
index.html
<body>
<div id="app">
<navbar></navbar>
<myc></myc>
</div>
<script src="dist/build.js"></script> <!-- Webpack endpoint -->
</body>
Navbar.vue
<template>
<h1>HELLO FROM NAVBAR</h1>
</template>
<script>
// Some logic here
export default {
name: 'navbar',
};
</script>
I coded as written in guide but neither of the ways to render a component is working
I just have blank page
I am using webpack+vue-loader
[UPDATE]
It works without components imports just rendering template
[UPDATE 2]
Got this message
[Vue warn]: Unknown custom element: <navbar> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
move your code from index.html to app.vue, index.html is a html file but not a vue file
try it , now it will be work , happy life.
//main.js
import Vue from 'vue'
import App from './App'
Vue.component('myc', { //gobal components
template: '<h1>Are you working?</h1>',
})
new Vue({
el: '#app',
template: '<App><App/>',
components: {
App
}
})
//index.html
<body>
<div id="app">
</div>
<script src="dist/build.js"></script>
</body>
//app.js
<template>
<div class="app">
<navbar></navbar>
<myc></myc>
<div
</template>
<script>
import navbar from 'path of Navbar.vue' //local components
export default {
name: 'app',
component:{
navbar
}
}
</script>
I've moved everything to App.vue
render: h => h(App) worked for me
This question already has answers here:
Angular2 Exception: Can't bind to 'routerLink' since it isn't a known native property
(12 answers)
Closed 6 years ago.
yes, this is probably the hundredth time some one experiences this problem, but no solution worked for me...
I am using angular 2.0.0 rc and nothing will work, I guess I am missing something, but I have no idea what
this are my files, they all transpile correctly, and yes I tried using the not deprecated route, and yes I did it according to the documentation, both don't work.
app.component.ts
import { Component, OnInit } from '#angular/core';
import {Routes, Router, ROUTER_DIRECTIVES} from '#angular/router';
import {LoginComponent} from './login/login.component';
import {HomeComponent} from './home/home.component';
#Component({
selector: 'my-app',
template: `
<h1>{{title}}</h1>
<nav>
<a [routerLink]="['/login']">login</a>
<a [routerLink]="['/home']">home</a>
</nav>
<router-outlet></router-outlet>
`, directives: [ROUTER_DIRECTIVES]
})
#Routes([
{ path: '/login', component: LoginComponent},
{ path: '/home', component: HomeComponent},
])
export class AppComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() {
this.router.navigate(['/home']);
}
}
main.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
import { ROUTER_PROVIDERS } from '#angular/router';
import { AppComponent } from './components/app.component';
bootstrap(AppComponent, [ROUTER_PROVIDERS]);
index.html
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
the rest of the files are pretty much a copy paste from the tutorial, so I won't spam with more code...
Update, I will add that for some reason npm logs don't send a GET request to #angular/routes-deprecated/... but they do send it to other modules.
however it is included in the package.json and systemjs.config.js
I think I know what the problem is, I am not sure what is causing it though
as you see there is no routes folder in the chrome assets. Therefore it makes sense it won't know it - however the node_modules in the project files is there, it is specified in the systemjs.config.js just like any other module...
They have deprecated the RC2 router: http://angularjs.blogspot.com.au/2016/06/improvements-coming-for-routing-in.html
I used the 3.0.0-alpha.7 version.
Based on their example I also made an app.routes.ts file:
import { provideRouter, RouterConfig } from '#angular/router';
import { FooComponent, BarComponent, BazComponent } from './components/bunchOComponents.ts'
export const routes: RouterConfig = [
{ path: 'foo', component: FooComponent },
{ path: 'bar', component: BarComponent },
{ path: 'baz', component: BazComponent }
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes)
];
I then used this in my main.ts file:
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './components/appcomponent.ts';
import { APP_ROUTER_PROVIDERS } from './app.routes';
bootstrap(AppComponent, [
APP_ROUTER_PROVIDERS
])
.catch(err => console.error(err));
HTH
Since RC.0 angular changed the router to a new implementation, which means that a lot of the examples available online are of the old router.
If you are using #RouteConfig it's the old router.
And it's that one that is available at #angular/router-deprecated
The new router uses #Routes and is available from #angular/router
Otherwise the importing of the ROUTER_DIRECTIVES and ROUTER_PROVIDERS are the same.
Other changes that are significant between the releases are.
the new router doesn't support named routes.
Routes
Before:
import {RouteConfig} from '#angular/router-deprecated';
#RouteConfig([
{path: '/myroute/:id', component: MyRoute, name: 'MyRoute'}
])
After:
import {Routes} from '#angular/router';
#Routes([
{ path: '/myroute/:id`, component: MyRoute }
])
routerLink
The routerLink directive also changed, and doesn't take an object as a second parameter to specify path variables such as id
Before:
<a routerLink="['MyRoute', {id: 1}]">Link</a>
After:
<a routerLink="['/myroute', 1]">Link</a>
Angular needs the [...] around the property name to indicate that it is a binding it needs to resolve. The [...] in the value is only to make Angular parse the assigned value as array.
<a [routerLink]="['/login']">login</a>
<a [routerLink]="['/home']">home</a>
This doesn't explain the error message you get because the error message indicates binding to a property that doesn't exist, while my correction is to make Angular actually do the binding.
This is a minimal reactjs application which, when bundled using webpack and then run, gives the following error from the browser console:
Uncaught ReferenceError: snapapp is not defined
Can anyone suggest why?
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
</head>
<body class='section'>
<div id="app"></div>
<script type="text/javascript" src="./build/snapapp.js"></script>
<script type="text/javascript">
(function () {
var mountNode = document.getElementById('app');
snapapp.start(mountNode);
})();
</script>
</body>
</html>
index.js
import { render } from 'react-dom';
import rootLayout from './src/components/ApplicationLayout.jsx';
import hello from './src/components/hello.jsx';
export function start(mountNode) {
render(<rootLayout />, mountNode);
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './index.js',
output: {
path: 'build',
filename: 'snapapp.js',
libraryTarget: "umd"
},
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
}
};
src/components/hello.jsx
import React from 'react';
class Hello extends React.Component {
render() {
return <h1>Hello</h1>
}
}
You are exporting snapapp from your module, but you aren't importing/requiring it anywhere, it doesn't exist as a global variable.
You are exporting as a UMD file format. If you need to inline code within your index.html file then you will need to either use a library like Require
Alternative you can:
Output to var
Change umd to var, you can read about it here, this will add your library onto the window global object. Allowing you to call it like you are within your html file.
output: {
path: 'build',
filename: 'snapapp.js',
libraryTarget: "var"
}
Place your bootup script into your file bundle
Unless there is some special reason I would move the bootup script into your index.js file. There is no reason you can not get the mount point from within the file. This also a very common pattern for what you are trying to do.
import { render } from 'react-dom';
import rootLayout from './src/components/ApplicationLayout.jsx';
import hello from './src/components/hello.jsx';
render(<rootLayout />, document.getElementById('app'));