How to load javascript es6 module determined at runtime? - javascript

I am developing a SPA which contains multiple dashboards. Each dashboard is a set of Web Components respecting a layout. These components are not known statically. They are determined at run-time.
What I want to achieve is the following scenario:
Application starts.
The application performs XHR to fetch dashboards representations from a REST service.
User sees dashboards listed by name.
User clicks on a dashboard item. (say dashboard 1)
The application determines the necessary components needed to load dashboard 1 (web components)
Load web components and their dependencies.
I am pretty aware of loading web components dynamically which was answered here
My actual problem is
how to load a web component with their dependencies at run-time
without having to load duplicate dependencies?
Are there any module formats or practices to follow when packaging the
web components?

If you have a mapping from dashboard to the module that implements it, then you can just dynamic import() the necessary module. The JS module system will take care of not loading modules that have already been loaded, so common dependencies like lit-element will only be loaded once.
This deduplication works based on URL, so you have to make sure that you have one copy of a dependency installed via npm. npm dedupe will attempt to deduplicate your node_modules/ folder, and npm ls will let you see the dependency tree.
All current browsers support dynamic import(), and most bundlers do too - as long as the argument is a string constant. This means that you can't compute the module URL based on the dashboard if you want to use a bundler. You need something like:
const dashboardLoaders = {
'dash-1': () => import('./dashboards/dash-1.js'),
'dash-2': () => import('./dashboards/dash-2.js'),
// etc...
};

Related

Building configurable react app with additional environment variable

I'm building an app that has some variations. The core of an app is the same but for now, I need to develop some parts of the app in different way, like another color scheme, different photos etc.
My Question is: Is there any possibility to build an app with specified instance by env variable? For example, I have set of photos provided as below.
[{
"photo1":{
"path":"my_path_to_file1",
"instanceToDeploy":"instanceABC"
}
},
{
"photo2":{
"path":"my_path_to_file2",
"instanceToDeploy":"instanceCBA"
}
}]
And for now, I would like to build my app like
npm run build instanceCBA
After this operation, I want to have build version of an app only with photos/whatever I will include in build command.
If elements are not tagged - I would like to build them anyway.
Is there any way to do this in React or something similar to this idea?
My previous attempt to this, was building the app on a few separated branches. Of course, unique changes was written without affecting another instances, but in situation when I've written the code which have to be on all instances - I have to actualize all the branches.
My main desire is to build some configurable elements that depends of choosen instance in my app.
Thanks for all possible help.
There are several options of how you can do it:
#1 (the easiest way)
If you use create-react-app boilerplate for your project you can use '.env' file for setting environment variables. You can find more info about it here: https://create-react-app.dev/docs/adding-custom-environment-variables/
#2
You can pass the parameter from your scripts that you defined in the package.json file. For example, let's say your scripts section looks like this:
"scripts": {
"build": "webpack --myInstance instanceCBA",
}
In this case in the webpack.config file you can read your parameter via process.argv array:
const instancePrefixInd = process.argv.indexOf('--myInstance');
let instance = '';
if (instancePrefixInd >= 0) {
instance = process.argv[instancePrefixInd + 1];
}
Then you can use this value in you webpack.config to specify details of the build or pass it directly to the app via setting 'process.env' variables (e.g process.env.MY_INSTANCE)

Combining Static Sites + Client Side Rendering (React, Gatsby)

I want to build a web app with React.
When users visit the site, they will see a Landing Page, can go to a Pricing Page, an About page, a Blog. etc. They can also Sign Up or Log in and then there's the actual app. I would like render certain pages (Landing,Pricing,About,Blog) statically, but would like to leave everything behind the SignUp/Login-Wall client-side rendered.
(First, because it cannot be static, since this is dynamic content. And also, because I do not care about SEO here anyways, so a major reason for next.js falls away, since the app is behind a SignUp/Login Wall anyways.)
Questions: First of all: Does this make sense? And secondly: How could I implement something like this? I haven't found anything online! Is this unheard of? I would like to use Gatsby.js for my static content, but I am not sure how to bring the client-side-rendered bit into the mix. I have worked with create-react-app before, which does client-side-rendering, - but I am not sure how I would go about the implementation?
I will try to explain the process behind jamstack-hackathon-starter (which #ksav commented).
It is a starter template for gatsby that allows you to save static pages in-
conjunction with dynamic pages (client-side react app) - a "Hybrid Gatbsy App".
Manual Steps:
1. Create a folder src/app which will contain your client-side react app.
2. Create a file in src/pages called app.js, with the following contents:
// I'm using create-react-app's structure
import App from '../app/src/App' // make sure this path corresponds to your path
export default App
Now install gatsby-plugin-create-client-paths:
npm install --save gatsby-plugin-create-client-paths
Configure it by adding it to gatsby-config.js like so:
plugins: [
{
resolve: `gatsby-plugin-create-client-paths`,
options: { prefixes: [`/app/*`] },
},
...
This will result in everything within /app to only be rendered in the browser (ie client-side).
Go to your browser after building (gatsby develop) and check /app
According to npmjs
The plugin gatsby-plugin-create-client-paths is deprecated.
https://www.npmjs.com/package/gatsby-plugin-create-client-paths
This plugin's functionality is now built-in to Gatsby.
Use the File System Route API: https://gatsby.dev/creating-client-only-routes.
This package will no longer receive updates.

How to import Parcel JS generated bundles into "legacy" application?

I'm working with an application with a front end built using old school techniques (jQuery and direct DOM manipulation) and I would like to move it over to ES8 and React. Since this is a rather large and complex application, this move will have to be gradual, meaning both the legacy code and React code will have to live side by side for some time.
The legacy code uses a home brew "module loader", which need to keep working. I've been looking at using Webpack and its configuration option libraryTarget: 'var', which basically outputs each entry point into a global variable. This works but the performance (build time) of Webpack isn't good enough so I have been looking at using ParcelJS instead.
Is it possible to achive something similar as Webpack's libraryTarget: 'var' with ParcelJS? Basically, in a "legacy HTML file" (which often times is server generated and may contain data I need to pass on to the ES8 modules), I would like to be able to do somethings along lines of
<script src="dist/js/ABundle.js"></script> <!-- Bundle created by ParceJS -->
<script>
var data = {/* JSON generated by server */};
var ABundle = require('ABundle'); // Export defined in ABundle.js.
ABundle.render(data); // Function exported in ABundle.
</script>
Note that i cannot pass my HTML files as entry points to ParcelJS as they contain references to Javascript files using the homebrew module loader which won't play nice with ParcelJS. I only want to pass the ES8 modules as entry points to ParcelJS and use them side by side with the home brew module loader.
EDIT: Clarified that legacy HTML is in fact server generated.

Attempting to load a JavaScript sdk into an Angular2 application. Can't find all dependencies

I'm attempting to make use of this library: https://github.com/MagicTheGathering/mtg-sdk-javascript in an Angular2 application.
Unfortunately, I've been going in circles trying to load it into my application.
Firstly, on the TypeScript side if I import it using:
import { } from 'mtgsdk';
there are no types to load into the {}.
If I attempt to load it using something similar to:
import * as mtg from 'mtgsdk'
I'm unable to because it says that it's unable to find a module named mtgsdk.
I've installed the module using
npm install --save mtgsdk
Also, npm installs work fine for other modules.
The application compiles fine if I load it in using require via something similar to this:
var mtg = require('mtgsdk');
Taking that approach, I'm able to compile and launch but in the browser I get a number of errors about modules that it can't find. I figure they are prerequisites for the sdk that didn't get loaded so I start bringing them in via package.json.
For every one that I bring in, I then have to go to systemjs.config.js and add an entry pointing to the module's entry point and often have to specify a default extension using blocks like this:
pointer
'mtgsdk': 'npm:mtgsdk/lib/index.js',
'request-promise': 'npm:request-promise/lib/rp.js',
'ramda': 'npm:ramda/dist/ramda.js',
'emitter20': 'npm:emitter20/index.js',
'bluebird': 'npm:bluebird/js/browser/bluebird.js',
'request': 'npm:request/index.js'
default extension
'request-promise':
{
defaultExtension: 'js'
}
I'm not sure if that's the right approach though because the more dependencies I add, the more that I end up requiring. At one point I had literally gotten up to 50 extra dependencies added because every time I launched, the browser console would find more that were needed.
Is there any easier way to load all of these in?
Also, some of them (such as tough-cookie and request-promise-core) were very problematic to load and I couldn't get the browser console to stop complaining about them. Finally, some of them seemed very basic such as url, http, https. Those seem like they should already be present.
Using systemjs was utilized in the previous versions of Angular 2, However Angular 2 has evolved to Angular 4, with super new features like Angular CLI.
I recommend your use Angular CLI, with #angular/cli.
Importing Node modules
Since mtgsdk is a node-module, you can easily import it using
import * as mtg from 'mtgsdk'
However for your program to compile, you must install a type definition for it. or declare one for it in /typings.json or your app might not build.
Importing Client Scripts
For client scripts like firebase.js you won't need to add client scripts as entries in systemjs.config.js again.
Using #angular/cli, you would easily add them in the scripts[] array in your angular-cli.json for automatic compilation.
Then access them like this
declare const firebase: any;
Here is a quickstart tutorial to set up Angular with #angular/cli.

Create directories and files from a template for rapid development with node/npm

I am trying to setup a shortcut to generate new components. For example if I had a bunch of React or Angular components that had a particular dir/file structure and included sample code for a new component. Is there a way to do this with node? It's quite time consuming to keep adding the same directories and files whenever I need to create a new component.
I usually do this in a convoluted but workable way with bash and aliasing but would like to use node, ie. npm run component myNewComponent where 'myNewComponent' would act as the function name within a myNewComponent.js file etcetc
I would have an example directory structure templated somewhere that node could pick up from or have it hardcoded in the node script file itself.
Yeoman does this with generators, but I would like to achieve it purely through node/node modules and full control over the code output and locations.

Categories

Resources