Is it possible to build a Standalone Vue app? - javascript

Is it possible to build a Vue app, which does not require Vue as as a dependency at runtime?
I.e. instead of the browser having to load the vue.js and the app like this
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://www.myxyzhost.com/my-app.js"></script>
have a my-app.js which already includes vue.js, so that including the script in a web page becomes a simple one liner?
<script src="https://www.myxyzhost.com/my-app.js"></script>

So, it was actually simpler than I thought:
I just created a separate entry file for webpack to consume like
my-custom-component-entry.js
and slammed everything I needed in there (vue and the respective component):
// This is the actual solution, I was looking for.
import Vue from 'vue';
import MyCustomComponent from './components/my-custom-component.vue';
new Vue({
components: {
'my-custom-component': MyCustomComponent
}
}).$mount('#app'); // ya gotta have a #app element somewhere of course
And then I built it with webpack (I am not going into detail here).
Now everything is packed in on file. No separate Vue runtime, which a customer might need to install. All that's necessary is:
<script src="https://www.myxyzhost.com/dist/my-custom-component.js"></script>
And yes, as always, this screws up, if you don't add the proper polyfills for internet explorer, but I take that for granted.
The important thing: for modern browsers it's a one liner which makes it easier to sell. That was all I needed.

Related

Vue3 documentation example codeblocks are strange

All throughout the Vue 3's documentation, they do the following when showing example code in a component:
Vue.createApp({})
I've never had to do this though, I simply use
<script>
export default {
name: 'example-component-xd'
}
</script>
What am I missing here? I just started learning Vue 3, and I haven't learnt any other versions of Vue before. This question is more just a curiosity I have, as it doesn't impact my ability to understand the documentation, but I thought that it may have something to do with the history of Vue, ES6 or best practices etc. Here is another example:
In Vue 3, Vue.createApp({}) replaces new Vue({}) from Vue 2. This line of code is typically in your entry file, where you mount the app (not in your component files).
The code in the <script> tag you showed is for single file components, and you can continue using that style. Never would you use Vue.createApp() or new Vue() in those single file components.
You can checkout an example Vue 3 app that shows Vue.createApp() in src/main.js, while the single file components in src/components use the Options API that you're also using.

Converting a common js global namespace A-Frame project into es6 modules

I have an A-Frame project with a primary component street that also depends on other components and helper functions from the same repo.
Currently using the street component in an A-Frame scene requires importing 8 separate js files from the same repo each with their own <script> tag. (code / show page)
Instead, I would prefer a simpler structure to import just one file, but I'd rather not use a bundler such as webpack. I think there is an ES6 approach but I'm confused about how to go about leveraging ES6 imports while still allowing the components to access functions from other files. In other words, how to get the imported files into the same namespace.
This question helps but the comments clarify the imported functions are not added to the global namespace automatically:
ES6 import equivalent of require() without exports
Maybe the structure would be something like this?
// index.html
<script src="src/street.js" ></script>
<a-scene>
<a-entity street="dosomething"></a-entity>
</a-scene>
// helperFunctions1.js
function coolHelperFunction1a (variable) {
// useful code
}
// street.js
import 'helperFunctions1.js'
import 'helperFunctions2.js'
AFRAME.registerComponent('street', {
coolHelperFunction1a (variable);
})
That probably won't work, what's the right way to do it?
A-Frame and ES Modules don't play well together, and I don't think there's a solution without using a bundler like Webpack.
In short, if you want to have a single <script> element for your entire app while still organizing your code well, I'd recommend Webpack, with the generated bundle being loaded synchronously in the <head> of your HTML document. Webpack can consume ES Modules, so you're still free to use those with the build process.
More detail on why native module loading won't work:
Your code would need a few changes for native ES Module usage, but the first one presents a problem: the <script> elements loading your modules need the type="module" attribute. This has a side effect: the browser treats modules the same way it treats traditional script tags with the defer attribute, meaning the script is executed after the DOM has been parsed. This is by design, as it leads to better initial page performance. Unfortunately A-Frame expects to run before the DOM has been parsed, and further it expects that you've initialized all of your components, systems, etc. before it runs. That is why they recommend putting the a-frame script in the <head>, and you'll notice there is no defer attribute.
A-Frame is kind of going against modern web performance advice, but it has a good reason: it doesn't want the browser to render the HTML before it runs, since its using the HTML for its own purposes.
This all means using native ES modules directly in the browser isn't going to work for an A-Frame app.
The suggested structure above needs a few fixes.
First, add export to the helper functions. For example,
function helperFunction (variable) {
code (variable);
}
changes to
export function helperFunction (variable) {
code (variable);
}
(See How can I export all functions from a file in JS?)
In street.js we also need to make sure to reference the module object it's imported as (See MDN Creating a module object)
We also need to change the <script> tag to include type="module" to use import and export keywords.
Here is a revised structure:
// index.html
<script src="src/street.js" type="module"></script>
<a-scene>
<a-entity street="dosomething"></a-entity>
</a-scene>
// helperFunctions1.js
export function coolHelperFunction1a (variable) {
// useful code
}
// street.js
import * as helperFunctions1 from 'helperFunctions1.js'
import * as helperFunctions2 from 'helperFunctions2.js'
AFRAME.registerComponent('street', {
helperFunctions1.coolHelperFunction1a(variable);
})
Another option, don't use ES6 Modules and use webpack instead. This is a nice example of a webpack A-Frame component project:
https://github.com/supermedium/superframe/blob/master/components/state/

How to build a JS module that can be used on the page directly?

I am the author of vue-sequence. This library is built with vue-cli and it export a library in umd format. To use this library, I have to use webpack to make it work on a web page, something like:
import { SeqDiagram, Store } from "vue-sequence";
...
Vue.use(vuex);
Vue.component("seq-diagram", SeqDiagram);
let store = new vuex.Store(Store);
A complete example of using it can be found at here: https://codesandbox.io/s/5v4v78w1wk.
I would like to be able to use it directly on a page (but still support using it as a node module), like:
<script src="vue-sequence.js" />
<script>
vueSequence.processAll()
</script>
I understand I would need to define this processAll() method somewhere. My question is about how to package this library.
I tried a few things. I think I know how umd works better. If we directly include the umd library on a web page, the library will create a field on the global window variable (in this case vue-sequence and referable via window['vue-sequence']).
With the following html configuration
<title>vue-sequence demo</title>
<script src="./vue-sequence.umd.js"></script>
<script>
console.log(window['vue-sequence'])
</script>
It will print out the exported module. Knowing about this is enough for me to continue working on a solution to add the processAll() fuction.

Laravel and VueJS - where\how to put instance and components

I have a simple, probably silly doubt about this basic thing using Vue not for an SPA:
Considering that Vue in my project is used to make small pieces interactive (tables, lists), and general filtering of database records, should I create a Vue instance for every component and add <div id="app"> in the places I need those things
...
<body>
....
<div id="nav">...
....
<div id="app">
<component></component>
</div>
app.js
const table = new Vue...
const calendar = new Vue...
Or should I make a generic #app div right after the body tag, containing all the site and, inside that, inserting the single components to then manage everything in a single new Vue instance?
<body>
<div id="app">
<div id="nav>....
</div>
<div id="anotherDiv">
...
...
</div> <!-- #app div -->
</body>
app.js
const app = new Vue...
It is probably easier to have a generic #app in your root div that will contain all of your site. Then if you want to add more components, then all you have to do is create a vue component and register it. To register a new component to your Vue instance you can use the following code where you create a main.js file.
Vue.component('your-component-name', require('PATH TO YOUR COMPONENT'));
After your component is registered you can use it anywhere in the #app body.
There are many things to consider here and all answers will be somewhat subjective, so keep that in mind. I don't think that any single way is the "correct" way to do it. I have found that the simplest implementation is to have a single Vue instance in app.js, and then build your components and use them wherever you want in the app div. However, this can be overkill and may affect you negatively in a couple of ways.
As one example, if you are not 100% committed to using Vue, then it's most likely that you also want to use jQuery and maybe even some jQuery plugins somewhere else in your app. jQuery and Vue do not play very nicely together unless you are instantiating the jQuery within Vue components. For this reason, if you plan to utilize other javascript libraries such as jQuery, then you might consider using individual instances of Vue with smaller scopes wherever you need to use a component.
If, however, you use Vue to help with some global tasks, such as line-clamping or truncating, then you really are best served by having a global install.
As far as other considerations, such as overhead, I believe that either method would probably just about be even. When you load globally, you get the benefit of browser caching even though the script is on each page. When you load page-by-page, you get the benefit of not having to load the scripts everywhere and only using them as you need them. In either case, overhead is pretty minimal for Vue on the modern web, so I don't think this should play into your decision at all.
Those are my thoughts.
You can do like this:
// Imported components
import examplecomponent from './components/ExampleComponent.vue';
import adduser from './components/AddUser.vue';
and for call vue components in laravel view:
<div id="app">
<examplecomponent ></examplecomponent>
</div>
<script src="{{asset('js/app.js')}}"></script>
For more basic information:
Laravel and VueJS - where\how to put instance and components

Dynamic loading of modules and components at runtime in Angular 4

I've been looking to develop a method for loading modules and/or components into an AOT-compiled Angular 4 application and been stymied by a variety of solutions that never quite seem to get me where I want to be.
My requirements are as such:
My main application is AOT compiled, and has no knowledge of what it is loading until runtime, so I cannot specifically identify my dynamic module as an entry component at compile time (which is explicitly necessary for the 'dynamic' component loading example presented on Angular.io)
I'd ideally love to be able to pull the code from a back end database via a GET request, but I can survive it simply living in a folder alongside the compiled site.
I'm using Webpack to compile my main application, breaking it into chunks - and so a lot of the SystemJS based solutions seem like dead ends - based on my current research, I could be wrong about this.
I don't need to know or have access to any components of my main application directly - in essence, I'd be loading one angular app into another, with the dynamically loaded module only perhaps having a few tightly controlled explicit interface points with the parent application.
I've explored using tools like SystemJsNgModuleLoader - which seems to require that I have the Angular compiler present, which I'm happy to do if AOT somehow allowed me to include it even if I'm not using it elsewhere. I've also looked into directly compiling my dynamic module using ngc and loading the resulting ngfactory and compiled component/module, but I'm not clear if this is at all possible or if so - what tools Angular makes available to do so. I have also seen references to ANALYZE_FOR_ENTRY_COMPONENTS - but can't clearly dig up what the limitations of this are, as first analysis indicates its not quite what I'm looking for either.
I had assumed I might be able to define a common interface and then simply make a get request to bring my dynamic component into my application - but Angular seems painfully allergic to anything I try to do short of stepping outside of it alltogether and trying to attach non-angular code to the DOM directly.
Is what I'm trying to do even possible? Does Angular 2+ simply despise this kind of on the fly modification of its internal application architecture?
I think I found an article that describes exactly what you are trying to do. In short you need to take over the bootstrap lifecycle.
The magic is in this snippet here.
import {AComponentNgFactory, BComponentNgFactory} from './components.ngfactory.ts';
#NgModule({
imports: [BrowserModule],
declarations: [AComponent, BComponent]
})
export class AppModule {
ngDoBootstrap(app) {
fetch('url/to/fetch/component/name')
.then((name)=>{ this.bootstrapRootComponent(app, name)});
}
bootstrapRootComponent(app, name) {
const options = {
'a-comp': AComponentNgFactory,
'b-comp': BComponentNgFactory
};
https://blog.angularindepth.com/how-to-manually-bootstrap-an-angular-application-9a36ccf86429

Categories

Resources