How to bundle react components which would be needed dynamically? - javascript

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

Related

Building a Webpack 4 Config for SASS (Compilation, Minification in Prod), JS (Concat + Minification), and Multiple Vue Single Page Applications

Trying to setup a webpack setup for my entire resource generation workflow in our app. I don't need any hot reloading, browsersync, etc. Just needs to watch for changes, and rebuild depedent objects when changes are made. File structure looks like this:
(I apologize for the image I seriously looked up other methods to post structure, but nothing was working on the preview, I can post a fiddle-or-codepen with this output in a comment afterwards)
The only areas of note are:
1) Each folder underneath vue-spas each Single-Page Mini App (SPAs) generates it's own output file of the app.
2) All items in constructs underneath js are concat and minified into one output file (/dist/js/main.min.js) but every item underneath js/components/ just renders a minified and mangled version of that file
Lastly, I understand this is probably a difficult question to wrap around, but I have Gulp doing some of it now, and Webpack doing the Vue compilation, just trying to see if it's possible to consolidate into just webpack and let it do the work.
Thanks for any assistance.
There are a few approaches. The simplest would be to add a key for each app in the entry point configuration in your webpack.config.js file.
That would look like this in your webpack.config.js file:
module.exports = {
entry: {
app1: './vue-spa/vue-spa1/app.js',
app2: './vue-spa/vue-spa2/app.js'
// etc
}
};
This will output individual directories in your dist for each with a nicely bundled app file.
By default, if you pass in a production variable to your webpack build command it'll apply all the optimizations you're looking for. If it's lacking out-of-the-box, there's likely a loader that can handle whatever optimization you need.
For Sass, you can add sass-loader to your webpack file:
https://github.com/webpack-contrib/sass-loader
Your devServer can just watch your vue-spa directory recursively for changes.
Another approach is to use lerna -- though that would require additional configuration, and is only necessary in your situation if you're in an enterprise environment where each individual app is being shipped out to a private NPM registry, and require individual semver.

How to split code into several bundles with Vue CLI3

I have a Vue project using TypeScript and built by Vue-CLI3.
What I'm trying to achieve is to get Webpack to build separate bundles for my workers. I've read about Webpack Code Splitting and about configureWebpack in vue.config.js, but so far had no luck in putting them together.
The project setup is the standard vue create type. I have a ./src/main.ts as the main entry point and a bunch of TypeScript modules, I want as separate bundles with their own dependency trees (I'm fine with code duplication if it can't be avoided).
I'd like to get
./dist/js/all main stuff
./dist/js/workers/worker1.6e3ebec8.js
./dist/js/workers/worker2.712f2df5.js
./dist/js/workers/worker3.83041b4b.js
So I could do new Worker(worker1.6e3ebec8.js) in the main code.
I could launch workers from the main package by generating javascript code, putting it into a blob and instantiating from that, but it looks rather awkward. Besides, my worker code import other modules, so it doesn't seem to be an option anyway.
I'm quite new to all of this, so maybe I'm not even heading in the right direction.
What is the usual way of doing that on this stack?
You can use import(), it will return a Promise and will resolve your module.
As you are using Vue-CLI 3, webpack is ready and it should split your bundle automatically.
const moduleName = 'coolModuleName'
import (
/* webpackChunkName: "[moduleName]" */
`#/my/module/path/${moduleName}.js`
).then(moduleCode => {
// use your module
})
// load them in parallel
const getModuleDynamically(path, moduleName) => import(
/* webpackChunkName: "[moduleName]" */
`#/${path}/${moduleName}.js`
)
Promise.all([
getModuleDynamically(path, moduleName1),
getModuleDynamically(path, moduleName2),
getModuleDynamically(path, moduleName3)
])
Got there! #aquilesb's answer did help, although I've failed to get getModuleDynamically() from the answer working after plenty of experimenting.
Update: Looks like with this solution I'm not able to use imports of npm modules. I've tried experimenting with worker-loader but haven't got anywhere so far.
Here are a few takeaways:
Create a separate webpack config for packing workers. The target: 'webworker' must be there. Call it with webpack --config ./webpack.config.workers.js, as Vue wouldn't know about that.
Create a separate tsconfig.json for workers TypeScript. The lib setting for workers must be there: "lib": ["esnext","webworker","scripthost"] as well as the proper include:[...]/exclude:[...] settings.
You may need to tell Vue to use the main tsconfig.json that has it's own "lib":["esnext","dom","dom.iterable","scripthost"] and include/exclude. This is done in vue.config.js, you will probably need to create it. I use chainWebpack configuration option of Vue config.
Let Webpack know you have dynamic loading by making calls to import() with static (i.e. not variable) names. I haven't found a way to do so in config file, but it doesn't matter: you can't help hardcoding the names somewhere, how else Webpack would know it has to bundle and split the code?
Somehow get the name(s) of generated files, as you must have at least one of them at runtime to do new Worker(filename). I used the --json option of Webpack CLI for that.
There are many ways all of this can be achieved. This is what this ended up looking like in my project:
Folder structure:
webpack.config.workers.js
vue.config.js
tsconfig.base.json
src/main/
src/main/tsconfig.json -- extends tsconfig.base.json
src/shared/ -- this code may be duplicated by the Vue app bundles and by workers bundle
src/workers/
src/workers/tsconfig.json -- extends tsconfig.base.json
webpack.config.workers.js: contains a single entry – the main worker file, that loads the other stuff.
entry: {
worker: './src/workers/worker.ts'
}
build.workers.sh: the script calls Webpack CLI and produces a JSON file with the resulting workers names (trivial actions on folders are omitted). The only one I need is called "worker". The rest is to be dynamically loaded by it.
#!/bin/bash
# Map entry name -> bundle file name
# "assetsByChunkName":{"entryN":"entryN.[hash].js", ...}
json=$(webpack --config ./webpack.config.workers.js --json $#|tr -d "\n\r\t "|grep -Eo '"assetsByChunkName":.+?}')
# Remove "assetsByChunkName"
json=$(echo "${json:20}")
echo $json
echo $json > "$target/$folder/workers.json"
Load workers.json at runtime. The other option would be to use it at compile time by providing Vue config with const VUE_APP_MAIN_WORKER = require("path to/workers.json").worker and using this env constant.
Now that we have the name of the main worker file, we can do new Worker("main worker file path we've got from webpack").
The main worker file contains the function that statically references other modules and dynamically loads them. This way Webpack knows what to bundle and how to split the code.
enum WorkerName {
sodium = "sodium",
socket = "socket"
}
function importModule(name: WorkerName): Promise<any> {
switch (name) {
case WorkerName.sodium:
return import(
/* webpackChunkName: "sodium" */
"workers/sodium"
);
case WorkerName.socket:
return import(
/* webpackChunkName: "socket" */
"workers/socket"
);
}
}
Use the postMessage/message event API to tell your main worker code what to load.
const messageHandler = (e: MessageEvent) => {
// here goes app-specific implementation of events
// that gets you the moduleName in the end
importModule(moduleName).then((work) => {
// do smth
});
};
Now, to the correct answer.
To achieve the following:
Using webworkers
Using both dynamic imports and normal imports in webworker code
Sharing code between webworkers and main app
I had to add a separate rule for worker-loader in vue.config.js and also to add babel-loader. It took me some time to find the correct solution, but I dropped the previous one (in my other answer) in the end. I still use separate tsconfig.js for main and for webworkers.
What I'm still not happy with, is that vue-cli–or rather fork-ts-checker plugin–doesn't seem to know the webworker-specific types in my worker classes (so I can't use DedicatedWorkerScope, for instance).

How to manage configuration for Webpack/Electron app?

I am using Webpack 2 and Electron to build nodejs application on Mac.
In my project in the root I have directory 'data' where I store configuration in a json like data/configurations/files.json (in practices there are different files with dynamic names)
After webpackaing though when I call: fs.readdirSync(remote.app.getAppPath()); to get files in the root I get only these packed: [ "default_app.js", "icon.png", "index.html", "main.js", "package.json", "renderer.js" ]
path.join(remote.app.getAppPath(), 'data/tests/groups.json'); called with FS ReadSync leads to an issue Error: ENOENT, data/tests/groups.json not found in /Users/myuser/myproject/node_modules/electron/dist/Electron.‌​app/Contents/Resourc‌​es/default_app.asar. So it seems that the whole data folder is not picked up by webpacker.
Webpack config is using json-loader and I did not find any documentation mentioning anything special about including specific files or jsons. Or do I have to reference json files in my code differently as they might be packed under main.js.
What is the best practice for Electron/Webpack for managing JSON config files? Am I doing something wrong when webpacking the project?
My project is based of https://github.com/SimulatedGREG/electron-vue using webpack/electron/vue
The Webpack Misconception
One thing to understand upfront is that webpack does not bundle files required through fs or other modules that ask for a path to a file. These type of assets are commonly labeled as Static Assets, as they are not bundled in any way. webpack will only bundle files that are required or imported (ES6). Furthermore, depending on your webpack configuration, your project root may not always match what is output within your production builds.
Based on the electron-vue documentation's Project Structure/File Tree, you will find that only webpack bundles and the static/ directory are made available in production builds. electron-vue also has a handy __static global variable that can provide a path to that static/ folder within both development and production. You can use this variable similar to how one would with __dirname and path.join to access your JSON files, or really any files.
A Solution to Static Assets
It seems the current version of the electron-vue boilerplate already has this solved for you, but I'm going to describe how this is setup with webpack as it can apply to not only JSON files and how it can also apply for any webpack + electron setup. The following solution assumes your webpack build outputs to a separate folder, which we'll use dist/ in this case, assumes your webpack configuration is located in your project's root directory, and assumes process.env.NODE_ENV is set to development during development.
The static/ directory
During development we need a place to store our static assets, so let's place them in a directory called static/. Here we can put files, such as JSONs, that we know we will need to read with fs or some other module that requires a full path to the file.
Now we need to make that static/ assets directory available in production builds.
But webpack isn't handling this folder at all, what can we do?
Let's use the simple copy-webpack-plugin. Within our webpack configuration file we can add this plugin when building for production and configure it to copy the static/ folder into our dist/ folder.
new CopyWebpackPlugin([
{
from: path.join(__dirname, '/static'),
to: path.join(__dirname, '/dist/static'),
ignore: ['.*']
}
])
Okay so the assets are in production, but how do I get a path to this folder in both development and production?
Creating a global __static variable
What's the point of making this __static variable?
Using __dirname is not reliable in webpack + electron setups. During development __dirname could be in reference to a directory that exists in your src/ files. In production, since webpack bundles our src/ files into one script, that path you formed to get to static/ doesn't exist anymore. Furthermore, those files you put inside src/ that were not required or imported never make it to your production build.
When handling the project structure differences from development and production, trying to get a path to static/ will be highly annoying during development having to always check your process.env.NODE_ENV.
So let's simplify this by creating one source of truth.
Using the webpack.DefinePlugin we can set our __static variable only in development to yield a path that points to <projectRoot>/static/. Depending if you have multiple webpack configurations, you can apply this for both a main and renderer process configuration.
new webpack.DefinePlugin({
'__static': `"${path.join(__dirname, '/static').replace(/\\/g, '\\\\')}"`
})
In production, we need to set the __static variable manually in our code. Here's what we can do...
index.html (renderer process)
<!-- Set `__static` path to static files in production -->
<script>
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
</script>
<!-- import webpack bundle -->
main.js (main process)
// Set `__static` path to static files in production
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
// rest of application code below
Now start using your __static variable
Let's say we have a simple JSON file we need to read with fs, here's what we can accomplish now...
static/someFile.json
{"foo":"bar"}
someScript.js (renderer or main process)
import fs from 'fs'
import path from 'path'
const someFile = fs.readFileSync(path.join(__static, '/someFile.json'), 'utf8')
console.log(JSON.parse(someFile))
// => { foo: bar }
Conclusion
webpack was made to bundle assets together that are required or imported into one nice bundle. Assets referenced with fs or other modules that need a file path are considered Static Assets, and webpack does not directly handle these. Using copy-webpack-plugin and webpack.DefinePlugin we can setup a reliable __static variable that yields a path to our static/ assets directory in both development and production.
To end, I personally haven't seen any other webpack + electron boilerplates handle this situation as it isn't a very common situation, but I think we can all agree that having one source of truth to a static assets directory is a wonderful approach to alleviate developer fatigue.
I think the confusion, (if there is any), might come from the fact that webpack not only "packs", embeds, things, code, etc... but also process content with its plugins.
html plugin being a good example, as it simply generates an html file at build-time.
And how this relates to the config file issue?,
well depending on how you are "requiring" the "config" file, what plug-in you are using to process that content.
You could be embedding it, or simply loading it as text, from file system or http, or else...
In the case of a config file, that I guess you want it to be parsed at runtime,
otherwise it's just fancy hardcoding values that perhaps you could be better simply typing it in your source code as simple objects.
And again in that case I think webpack adds little to nothing to the runtime needs, as there is nothing to pre-pack to read at later use,
so I would possibly instead or "require"it, i'll read it from the file system, with something like :
// read it parse it relative to appPath/cwd,
const config = JSON.parse(
fs.readfileSync(
path.join( app.getAppPath(), "config.json" ),
"utf-8"
))
//note: look fs-extra, it does all that minus the app.path plus async
and electron will read it from the file system , or if using Electron.require will read it from asar|fileSystem (in that order if I remember correctly, I could be wrong),
Webpack design philosophy is focused around very simple yet powerful concept:
Transform and bundle everything that is actually used by your app.
To achieve that webpack introduces a powerful concept of dependency graph, which is able to manage virtually any kind of dependencies (not only *.js modules) by the means of so-called loaders.
The purpose of a loader is to transform your dependency in a way that makes statement import smth from 'your_dependency' meaningful. For instance, json-loader calls JSON.parse(...) during loading of *.json file and returns configuration object. Therefore, in order to take advantage of webpack dependency resolution system for managing JSONs, start from installing json-loader:
$ npm install --save-dev json-loader
Then modify your webpack.config.js in the following way:
module.exports = {
...
module: {
rules: [
{test: /\.json$/, use: 'json-loader'}
]
}
...
};
At this point webpack should be able to resolve your JSON dependencies by their absolute paths, so the following should work (I assume here that you have a subdirectory config of your root context dir, containing file sample.json):
import sampleCfg from './config/sample.json';
But importing physical paths doesn't lead to elegant, robust and maintainable code (think of testability, for example), so it is considered a good practice to add aliases to your webpack.config.js for abstracting away your physical .config/ folder from your import statements
module.exports = {
...
resolve: {
alias: {
cfg: './config'
}
}
...
}
Then you'll be able to import your JSON config like that:
import sampleCfg from 'cfg/sample.json'
Finally, if you use SimulatedGREG/electron-vue Electron project template (as you mentioned in your post), then you have three webpack configuration files:
.electron-vue/webpack.web.config.js - use this config file if you use this template just for ordinary web development (i.e. not for building native Electron projects);
.electron-vue/webpack.main.config.js - use this file to configure webpack module that will run inside Electron's main process;
.electron-vue/webpack.renderer.config.js - use this file for Electron's renderer process.
You can find more information on main and renderer processes in the official Electron documentation.

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

Resolving alias in webpack

I am trying to resolve an alias in webpack but can't seem to figure out why this isn't working. I am using a library called GoJS. I have the below code in my module.exports of webpack:
resolve: {
alias: {
go: path.resolve(__dirname, './go.min.js')
}
}
This file is in my root project directory for now. At the top of my ES6 module I have:
import go from 'go';
I have also tried:
var go = require("go");
The library does seem to be loading. If I console.log(go) within the module, it returns an empty object. Do I need to load this file a different way because of how it is designed? Or is something wrong with my webpack settings?
Here is the javascript file I am trying to load
This is solved by updating GoJS to a later (1.5 or beyond probably) version, as it handles modules/requires/imports differently after that.

Categories

Resources