Using Vue without bundlers? - javascript

I am creating some experimental web sites that are using JavaScript without bundling. For dependency management I have used RequireJS until now, but I have started to use SystemJS recently since it has some very nice support for HTTP2. I have done some experiments so far on my custom set web server and results are great for the web sites I am creating. For example, first page render happens around 400ms, full page load at 800ms etc.
I am doing this because I want to take full advantage of HTTP2 and I want to lazy load only scripts that I am using at a certain moment. Code like that is easier to maintain, it’s cached better etc. At the moment there is a total craze about bundlers like Webpack, but that is not something I want to use.
Here is the question: is there a way to compile single Vue file / components by using Gulp and then load them with SystemJS as AMD or CommonJS modules?
edit:
This is what I want to achieve with SystemJS and Vue:
entry point JS file:
// SystemJS config
SystemJS.config({
/* ... */
baseURL: './',
map: {
// App
'app': 'scripts/app.min.js',
// Utils
'axios': 'scripts/vendor/axios/axios.min.js',
'modernizr': 'scripts/vendor/modernizr/modernizr.min.js',
// Framework
'vue': 'scripts/vendor/vue/vue.min.js',
// Components
'vueHelloWorld': 'scripts/components/hello/vueHelloWorld.js', // <- Compiled VUE component
'vueMenu': 'scripts/components/menu/vueMenu.js'
},
depcache: {
'vueHelloWorld': ['vue'],
'vueMenu': ['vue', 'vueHelloWorld']
}
/* ... */
)};
// Initially Load default scripts
require(['modernizr', 'axios', 'app']);
Vue components vueHelloWorld.js and vueMenu.js are end result, compiled into pure JS from single file templates vueHelloWorld.vue and vueMenu.vue.
After that initial file, app.min.js is loaded and it will have declarations to load rendered vue components.
This is what I don't know how to do - how to render separate files for each Vue component that I want to load in this manner?

If I understand the question correctly, all you are looking for is something that takes a single *.vue file and returns a single compiled *.js file. You could either try and write your own thing using https://github.com/vuejs/vue-component-compiler, or what I ended up doing is misusing rollup as my vue compiler, configuring it, so that it ignores all dependencies and therefore takes one vue component in and only compiles that one component. Here you can see the config that achieves that: https://github.com/ecosia/bazel_rules_nodejs_contrib/blob/master/internal/vue_component/rollup.config.js

It seems that Async components and webpacks code splitting are what you are looking for.
Here you find an article about using them:
https://vuejsdevelopers.com/2017/07/03/vue-js-code-splitting-webpack/

No, because single Vue file (*.vue) can only be recognized by vue-loader through webpack, SystemJS or AMD or CommonJS are totally unrelated to it, these three are modularity standards or ways to make your javascipts files organized.
Also u can write in this way.
a.component.js
var ComponentA = {
template: '#view-a',
}
b.component.js
var ComponentB = {
template: '#view-b',
}
then in your html file
<script type="text/x-template" id="view-a">
<div> .... </div>
</script>
<script type="text/x-template" id="view-b">
<div> .... </div>
</script>

Related

How to bundle react components which would be needed dynamically?

We have several applications deployed which were with plain html and js.
These applications should be completely independent modules without affecting other applications deployed.
But we should be able to load from one application to another if the situation needs which will be dynamically decided by business.
We were able to load different application screens by simply giving the relative path as there was no dependency bundling previously.
Now we are converting them to react applications with webpack as bundler.
Here we have to use dynamic import if we are going to need something dynamically. That also works on patterns which should be given at the build time.
So is there any way to achieve this kind of dynamic pattern using webpack bundler?
For importing screen components, code is something like below,
Promise.all(reqList.map(modulePath =>
{
return import(/* webpackMode: "lazy-once" */`../../../${modulePath}.jsx`)
})).then(modules => {doStuff()})
As they all are parallelly deployed applications we are trying to go back 3 folders (i.e, root folder like webapps in tomcat) and access the other application path, which will be derived dynamically in modulePath variable.
So while importing, webpack tries to import from the chunks which has already been loaded on first application launch. But this loaded chunks are not having the screens from other applications yet.
We have tried giving each jsx files as entry points in webpack which did created independent files but if we make them as entry files, they should be attached to the index.html manually, Which would cease export in jsx to work.
My wepack config is something like below,
function getEntries(pattern) {
const entries = {};
glob.sync(pattern).forEach((file) => {
let fileName = file.substr(0,file.indexOf("."));
entries[fileName.replace('src/', '')] = path.join(__dirname, file);
});
return entries;
}
let jsxFiles = getEntries('src/**/*.jsx');
console.log(Object.keys(jsxFiles));
module.exports = {
entry: jsxFiles,
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js',
chunkFilename: "AppId"+'.js'
}
}
The first application is loading fine as webpack is able to find the bundled chunks but when we try to load different application screen components, dynamic importing fails saying module not found.
Is there any way we can achieve this kind of dynamic imports?
Thanks for going through such a long post, I didn't had a choice but to explain.. :)
Essentially, you are looking for dynamic module loading. You would need to webpack each module separately.
To load them, you have several options
Use the browser's native import(), but IE, Edge, and Firefox don't support it, yet
Use a module loader library
SystemJS
RequireJS, although it's rather old
In case of going with a module loader, you need to webpack your modules to the corresponding System.register or AMD formats

Migrating from requirejs to es6 imports

I have a javascript app that uses requireJS to load its components. This is simple example of how it works:
require(['eventHandler'], function(eventHandler)) {
... // app code that uses the eventHandler in some way
}
It uses several components, but let's simplify it and pretend its only this one.
I have two different "versions" of my miniapp in 2 parts of the bigger web application we develop in my company. In order to improve reusability I came up with the following idea:
I have 2 files of require configuration that define the location of the modules the app needs to run and I can define the set of components it should use for each case.
Standard config:
require.config({
paths : {
// components
eventHandler : 'lib/eventHandlers/standardEventHandler',
...
});
Especial config:
require.config({
paths : {
// components
eventHandler : 'lib/eventHandlers/specialEventHandler',
...
});
When I load the app I do the following:
<script data-main="#standardConfigFile" src="/lib/require/require.js"
type="text/javascript" charset="UTF-8"></script>
And this is how I can load different components for each configuration. Currently I have 2 different ones but I expect to increase that number soon.
Now we are switching to es6 modules with native import and export and I wonder how can I migrate my current architecture to native js imports and exports and the documentation does not cover this particular problem.
Any ideas?
I found the answer, it's actually really simple. I only need to make an "importer" module.
In my main component I'll do:
import * as components from '#standardComponentsLoader.js';
And then do all the imports in standardComponentsLoader:
import * as eventHandler from '#standardEventHandler.js';
export { eventHandler };

Making Webpack register modules in RequireJS cache

Currently I'm using RequireJS for all my modules.
I'm considering using Webpack for my main project but need to load modules not known during build time. Like plugins.
One approach would be to use Webpack at build time and then use RequireJS at runtime. The only problem is that files loaded from Webpack bundle won't be found in the RequireJS cache.
If I manually register them it works:
import jQuery from 'jquery';
define('jquery', [], function() { return jQuery; });
But is there some easier way? Like Webpack generating code that does this?
I ended up writing a custom loader that added the code at the end of each file. Using window.define instead of define makes Webpack leave it intact for RequireJS.

How can I improve load performance of Angular2 apps?

Angular2 app is loading slow, how can I improve the performance on load?
I use Angular2, typescript with html5.
currently my app takes 4 seconds to load.
I host with Firebase and use cloudflare.
Things I'm doing / info:
I've compressed images.
I minify css
I minify js.
I use async on my scripts.
My scripts are in my .
The scripts are around 700kb
I used google speed test and get 65%
I used minified version of the libs I use e.g. bootstrap etc.
Using systemjs.
This is the seed app im using: https://github.com/mgechev/angular-seed
Flow:
When the app loads it shows a blue screen (this is the bootstrap css) and then 4 seconds later the app loads and works really fast. But takes 4 seconds to load. It seems the app.js file that systemjs minifies to is slowing the whole app, and not showing the views fast enough.
This is my website speed test:
https://www.webpagetest.org/result/161206_F5_N87/
This is my website:
https://thepoolcover.co.uk/
Let me know if you need more information about my app and any other things I can do.
A single page application generally takes more time while loading as it loads all necessary things at once.
I had also faced same problem and my team has optimized our project from loading in 8 seconds to 2 seconds by using following methods.
Lazy loading a module : Lazy loading modules helps to decrease the startup time. With lazy loading our application does not need to load everything at once, it only needs to load what the user expects to see when the app first loads. Modules that are lazily loaded will only be loaded when the user navigates to their routes. Angular2 has introduced modules in its final release RC5. See below for step-by-step guide.
Aot Compilation : With AoT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the app first.
It reduces the payload size : There's no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload. For more info see this.
Webpack : Webpack is a popular module bundler, a tool for bundling application source code in convenient chunks and for loading that code from a server into a browser. You can configure your Angular 2 web application with webpack (see this guide).
Remove scripts,stylesheet from index.html : Remove all scripts and stylesheet which are not needed in index.html. You can load these script dynamically in component itself by calling a service.
Make a file script.service.ts which can load any script on demand for that component
\script.service.ts
import { Injectable } from '#angular/core';
declare var document: any;
#Injectable()
export class Script {
loadScript(path: string) {
//load script
return new Promise((resolve, reject) => {
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = path;
if (script.readyState) { //IE
script.onreadystatechange = () => {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
resolve({ loaded: true, status: 'Loaded' });
}
};
} else { //Others
script.onload = () => {
resolve({ loaded: true, status: 'Loaded' });
};
};
script.onerror = (error: any) => resolve({ loaded: false, status: 'Loaded' });
document.getElementsByTagName('head')[0].appendChild(script);
});
}
}
This is just a sample code to load script dynamically, you can customize and optimize it by yourself according to your need.
For stylesheet you should load it in component using styleUrl.
Use Browser Caching : Your webpage files will get stored in the browser cache when you use browser caching. Your pages will load much faster for repeat visitors and so will other pages that share those same resources. For more info https://varvy.com/pagespeed/leverage-browser-caching.html
minimize the code in app.component.ts : minimize the code present in app.component.ts which always run when the app loads or reloads.
set data on app Initialization : if you are using same api calls multiple times in your project or in components,
or you are dependent upon same data in multiple component, instead of calling api multiple times what you can do is save
the data as an object in service on app initialization. That service will act as a singleton throughout the project and you
can access that data without calling api.
Lazy loading of modules step by step
Modular structure : We have to divide our App into separate modules. For example an app may have a user side and an admin side and each will have its own different components and routes, so we will separate this two sides into modules admin.module.ts and user.module.ts.
Root Module : Every Angular app has a root module class. By convention it's a class called AppModule in a file named app.module.ts , this module will import the above two module and also the AppComponent for bootstrap. You can also declare multiple components according to your need. Sample code in app.module.ts:
\app.module.ts
import { NgModule } from '#angular/core';
import { UserModule } from './user/user.module';
import { AdminModule } from './admin/admin.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login.component';
#NgModule({
imports: [UserModule, AdminModule],
declarations: [AppComponent, LoginComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
Routes : Now in your routes you can specify like the following
\app.router.ts
import { ModuleWithProviders } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { LoginComponent } from './login.component';
const routes: Routes = [
{ path: 'login', component: 'LoginComponent' }, //eager loaded
{ path: 'admin', loadChildren: './admin/admin.module#AdminModule' }, // Lazy loaded module
{ path: 'user', loadChildren: './user/user.module#UserModule' } //lazy loaded module
];
Now when the application loads, it will only load LoginComponent and AppComponent code. These modules will only be loaded when we visit /admin or /user routes. Hence it will decrease the size of payload for loading into the browser, thus resulting in fast loading.
Nesting Modules : Just like app.module every module has its own set of components and routes. As your project becomes larger, the nesting of modules inside module is the best way to optimize because we can lazily load those modules whenever we require.
PLEASE NOTE
Above code is only for explanation, please refer for full example
https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html
How about "code splitting".
From the Webpack site:
"For big web apps it’s not efficient to put all code into a single file, especially if some blocks of code are only required under some circumstances. Webpack has a feature to split your codebase into “chunks” which are loaded on demand. Some other bundlers call them “layers”, “rollups”, or “fragments”. This feature is called “code splitting”.
Link here:
https://webpack.github.io/docs/code-splitting.html
Note that the Angular CLI uses Webpack.
Also, make sure that if your app bootstraps with data calls, that you are not holding up the rendering of your components waiting on those calls to return. Promises, async, etc.
It is difficult to diagnose the precise problem you are having without hands-on to your entire code base and backend (as others have suggested, the problem may not be angular at all).
Having said that, I HIGHLY recommend you start using the angular-cli. It was designed by the angular team to accomplish all of the things you need to do in a easy-to-use command line interface. So my answer is predicated on the use of the angular-cli.
Here are the general things you can do to optimize your ng2 project for production:
1) Ahead of Time (AoT) Compilation - Bundling/Minification/Tree-shaking
Look, forget about the headache of configuring a bunch of gulp tasks to accomplish all of these things. The angular-cli handles Bundling/Minification/Tree-shaking/AOT compilation in one easy step:
ng build -prod -aot
This will produce the following js files in your "dist" folder:
inline.d41d8cd98f00b204e980.bundle.js
vendor.d41d8cd98f00b204e980.bundle.js
main.d41d8cd98f00b204e980.bundle.js
styles.4cec2bc5d44c66b4929ab2bb9c4d8efa.bundle.css
You will also get the gzipped versions of these files for MORE optimization:
inline.d41d8cd98f00b204e980.bundle.js.gz
vendor.d41d8cd98f00b204e980.bundle.js.gz
main.d41d8cd98f00b204e980.bundle.js.gz
Angular's AOT compilation will automatically do "tree shaking" on your code and get rid of any unused references. For example, you may use lodash in your project, but you probably only use a few lodash functions; tree shaking will trim away all the unused parts of lodash that are not needed in your final build. And most importantly, AOT compilation will pre-compile all of your code and views which means LESS time the browser needs to get the ng2 app rolling. Click here for more info on angular's AOT compilation.
2) Lazy loading parts of your app
If you further carve up your app into different parts, you do not need to load EVERYING when your app first loads. You can specify different modules for your application that then can be bundled (by the angular-cli aot compiler) into different chunks. Read up here to learn how to organize your project into modules that you can compile into chucks that are only loaded AS NEEDED. Angular-cli will manage the creation of these chunks for you.
3) Angular Universal
Now if you really want to make your load time EXTREMELY fast then you will want to consider implementing Angular Universal, which is when you compile your initial view ON THE SERVER. I have not used Angular Universal as I have been able to achieve fast load times with steps 1 and 2. But it is an exciting option in the ng2 toolset. Keep in mind you don't compile or run the ng2 app on the server, you compile the initial view serverside so the user quickly receives a jolt of html and thus the user PERCEIVES the load time to be very fast (even though a full load will still lag behind a little bit). This step does not obviate the need for the other steps. As a bonus, Angular Universal also is supposed to help with SEO.
4) Secondary bundling
If I am not using lazy loading, I usually go ahead and further bundle the distribution files that are generated from AOT compilation. Thus I create one main.bundle.js file that concats inline.js, vendor.js and main.js files. I use gulp for this.
because its SPA and angular 2 init too slow. thats it. plus RXjs, tons of polifills etc. AOT can help but a lot of angular2 libs do not work with it. angular universal realy helps
Build your angular app using following command to get maximum optimization benefits.
ng build --prod --aot --optimization --build-optimizer --vendor-chunk --common-chunk --extract-licenses --extract-css --source-map=false
Basically you will build in aot mode and use treeshaking with some optimization.
optimization: Enables optimization of the build output.
vendor-chunk: Use a separate bundle containing only vendor libraries.
common-chunk: Use a separate bundle containing code used across multiple bundles.
extract-css: Extract css from global styles onto css files instead of js ones.
build-optimizer: Enables #angular-devkit/build-optimizer optimizations when using the 'aot' option.
source-map=false: remove source map will also reduce bundle size
Try disabling source maps by running ng serve --sourcemap=false

Changing Vue.js from standalone to runtime-only build later in a project?

Went with the runtime-only build version of Vue.js for a new project. I saw in the docs that to switch to the standalone one needs to add an alias to webpack, like so:
resolve: {
alias: {
'vue$': 'vue/dist/vue.js'
}
}
At the moment, I don't need the compiler in my app. However, it's possible that at some point I will need to switch to the standalone build.
My question is:
Will it be a painless switch between runtime-only and standalone later or will it require heavy refactoring?
If it does, I might as well start with standalone and avoid refactoring later on.
standalone supports template option in components. For example, you can do this:
Vue.component('my-component', {
template: '<div>A custom component!</div>'
})
standalone also allows you to load vue.js from a CDN, like you would do with jQuery or any other javascript library.
runtime-only does not allow you to use template in component definition. So you need to create my-component.vue file and define template inside as detailed in Single File Components guide: http://vuejs.org/guide/single-file-components.html
Also you need to use vue-cli for development, if you are using runtime-only.
To switch from standalone to runtime-only, you will have to rewrite all the components into my-component.vue files, and start using vue-cli
To switch from runtime-only to standalone, there are no changes required.
Other than that, it is painless to switch between runtime-only and standalone.
My preference: runtime-only only mode, as it produces much smaller builds and theoretically performs better, as templates are pre-compiled. Also the sections in vue file are well organized and easy to read. Separate vue files for components also forces you to structure your app better.

Categories

Resources