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

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.

Related

How to load javascript es6 module determined at runtime?

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...
};

Is there a way to conditionally change main entry file in package.json?

I'm currently developing two applications in two different projects: a React component library to be used as a design system, and a React webapp to render pages using components from design system.
Inside my webapp, I import the components as following:
import { Button } from 'designsystem'
Inside the package.json of designsystem, my main entry points to /src/index.js where all my components are exported as a ES6 module. When I'm developing that's ok, because when I update a component in designsystem it reflects on the webapp and that's the desired behaviour.
Although when I try to build my webapp, it only works if I point the main entry of designsystem to the dist folder, which contains a bundled file with all the components as UMD. This way, I can't see the changes of the components inside my webapp unless if I build everything again.
I already tried to conditionally return the components module or dist content in /src/index.js in order to point to the correct content. But nothing worked.
My question is: Is there a way to conditionally change the main entry in package.json? If not, is there another solution for this?
EDIT: When the main is pointing to the source, I can work fine with it using npm link. My problem comes when I try to build the parent, unless I switch the main to the build folder.
The "main" entry in your package.json deserves to point to the build folder:
The main field is a module ID that is the primary entry point to your
program. That is, if your package is named foo, and a user installs
it, and then does require("foo"), then your main module's exports
object will be returned.
This should be a module ID relative to the root of your package
folder.
For most modules, it makes the most sense to have a main script and
often not much else.
Ref:https://docs.npmjs.com/files/package.json#main
The root of your package has nothing to do with your dev app. You should use npm link while developing and leave unchanged your main pointing to build folder.

Angular CLI 6: How to consume a library sub-project in the main application?

I've got an Angular 6 project that's made of up a main application, and a separate sub-project that is a library. I'm trying to consume this library from the main application, and I can't seem to get it working.
In the tsconfig.json, I have the following paths configuration:
"paths": {
"#my-company/my-package/*": "dist/my-package/*"
}
And then in the main app, I import the library like so:
import { ButtonModule } from '#my-company/my-package/button';
However, when I build the main application, I get tons of errors about not being able to find modules. For the above import statement, I'll get this error:
Module not found: Error: Can't resolve '/Users/jattardi/code/myproject/dist/my-package/button'
However, if I check the dist/my-package directory, there certainly is a button directory containing the type definitions.
The reason my imports have subpaths, e.g. #my-company/my-package/button instead of just #my-company/my-package is to make it tree-shakeable. Not sure this is possible. Since this is an Angular 6/ng-packagr generated build, do I lose this ability?
I was hit with the same error when trying to consume in the main application. My answer will not solve that case as I am trying to get my lazy loaded module, I moved into the new Angular6 library, to work.
I was able to publish my library project to npm and consume it in the main application as an npm dependency. For eg: #santony/ngx-material. May be as a workaround you could do that until this is resolved.
For those who are still facing this problem, there's a "how to" at ng-packagr's documentation:
https://github.com/ng-packagr/ng-packagr/blob/master/docs/secondary-entrypoints.md
Basically,
All you have to do is create a package.json file and put it where you want a secondary entry point to be created.
The contents of my_package/testing/package.json can be as simple as:
{
"ngPackage": {}
}
And also, in dev application, I've added the path reference to the secondary endpoint, so it worked:
"#my-company/my-library/another": [
"dist/my-library/another"
]

Best way to make webpack run a script in browser?

I want Webpack to execute a script (that is provided by my npm package) in the browser, without needing to include that script in my app. Currently, I am using webpack.config.dev.js to force it, like this:
module.exports = {
entry: [
paths.appIndexJs,
"./node_modules/my-dev-package/client.js"
]
}
client.js contains an IIFE that modifies the DOM. I want to avoid having to add conditional logic to my application to check for the environment, when I really just need something appended to the DOM in development. Is there a more standard way to get this same effect, without having to import client.js inside my app and conditionally run it there?
I am new to webpack, so if there is a standard way to do this or a commonly used plugin, that's what I'm looking for.

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.

Categories

Resources