Usually in micro-frontends environment you have each app deployed separately and so assets for different apps reside under different base public URLs.
Let's imagine that we have App1 and App2 and we deploy their assets to CDN https://cdn.com
.
This can bring us to the following files structure at CDN:
- app1
|- main.a34gf.js
|- chunk0.nvfg4.js
|- main.fg45s.css
|- assets
|- logo.df45.png
- app2
|- main.wgr5a.js
|- chunk0.sdt54.js
|- main.jh63g.css
|- assets
|- logo.df45.png
Considering that it's not the best practice to hardcode absolute URLs right within JS/CSS bundle (as it makes built code environment dependent) - we need to keep only relative URLs in the bundle and supply basic public path URL at runtime.
In our example App1 should receive https://cdn.com/app1/
while App2 requires https://cdn.com/app2/
to function
correctly.
Fortunately modern Webpack 5 supports automatic detection of the public path at runtime (based on the URL of the JS file). Or similar can be achieved with the use of SystemJSPublicPathWebpackPlugin.
However, all those approaches does not support SSR. All of them use URL of the currently executed JS file in order to try to determine public path of the bundle, and you simply don't have that data available during SSR.
There are several reasons we need it to be set correctly, here are some of them.
Client side rendering
file-loader
.Server side rendering
file-loader
.All you need to do to configure public path for your CSR bundle - is to use WebpackPluginsFactory
from ILC SDK.
// webpack.js
const ilcWebpackPluginsFactory = require('ilc-sdk').WebpackPluginsFactory;
module.exports = {
entry: 'src/client.entry.js',
output: {
filename: 'app.js',
libraryTarget: 'system',
},
module: { /* ... */ },
plugins: ilcWebpackPluginsFactory().client,
};
This plugin will set bundle's public path automatically using current URL of the JS file. So if main chunk of your JS bundle
has URL https://cdn.com/teamA/app1/index.fhg3r.js
- public path will be https://cdn.com/teamA/app1/
.
If you need have JS bundle at https://cdn.com/app1/js/index.fhg3r.js
and want public path to equal https://cdn.com/app1/
-
pass the following props to the ilcWebpackPluginsFactory:
ilcWebpackPluginsFactory({
publicPathDetection: {
rootDirectoryLevel: 2
}
}).client
Unfortunately it's virtually impossible to provide consistent with CSR solution that would work with every framework/use case. So for now we've decided to step away of the CSR/SSR consistent solution and use Node.js app environment variables as a source of public path for SSR bundle.
It works by setting ILC_APP_PUBLIC_PATH
environment variable to the process in which you execute your SSR.
This variable will be picked up by code injected by ilcWebpackPluginsFactory().server
Webpack plugins.
To make it work - you need to do the following:
// webpack.server.js
const ilcWebpackPluginsFactory = require('ilc-sdk').WebpackPluginsFactory;
const path = require('path');
const config = require('./webpack.js');
config.entry = 'src/server.entry.js';
config.target = 'node';
config.output.filename = 'server.js';
config.output.libraryTarget = 'commonjs2';
config.plugins = ilcWebpackPluginsFactory().server;
config.externals = [];
module.exports = config;
It's up to the App developers to choose how to deliver value of the ILC_APP_PUBLIC_PATH
environment variable to the app process.
Also there is an option to customize construction of the public path from the env variable. It's useful when you run dozens of apps
which store their assets at the same CDN. To achieve that - pass the following parameters to ilcWebpackPluginsFactory
:
ilcWebpackPluginsFactory({
publicPathDetection: {
ssrPublicPath: 'https://${process.env.CDN_DOMAIN}/app-folder/'
}
}).server;
Generated using TypeDoc