How to import url in css file from environment variable - javascript

I have index.css file in React app and I am importing an external css file as below.
#import url('https://externalurldev01.blob.core.windows.net/XXX/index.css');
And this url will differ for different env.
Dev : #import url('https://externalurldev01.blob.core.windows.net/XXX/index.css');
QA : #import url('https://externalurltest01.blob.core.windows.net/XXX/index.css');
PROD : #import url('https://externalurlprod01.blob.core.windows.net/XXX/index.css');
How can I dynamically do the import based on env.
For now I have a workaround of creating three index.css as index-dev.css,index-qa.css,index-prod.css file and import it conditionally from the js file.
But I am looking for some solution so that I need not create three files. Rather get the env from environment variable. Something like below
#import url('https://externalurl"+process.env.REACT_APP_ENV+"01.blob.core.windows.net/XXX/index.css');
But the concatenation is not working.

process.env is only available on the backend so you can not use it in css or js in browser. The way I usually do this is to populate the value on data-* attribute in html and then extract this attribute value in css using the attr() function or dataset property in js.

I am able to solve the problem.
I am dynamically importing the css file as below.
useEffect(() => {
var head = document.head;
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = window.REACT_APP_THEME;
head.appendChild(link);
return () => { head.removeChild(link); }
}, []);
Since the app is deployed in Kubernetes cluster, so getting setting the window variable from the configmap.

Related

How can I change the href of a Javascript created page after bundling with webpack?

I'm trying to use webpack with a project and I'm having trouble with dynamically created pages.
I have three dynamically created modules for a header, a footer ,and one other page.
Per example in header.js, I have a navbar with link such as "/src/html/about.html".
When I run the live server from the src folder I encounter no problem at all. The problem comes when I run webpack and I bundle everything into the dist folder. The paths inside the .js files to not change and my index.html can not load them up properly.
header.js looks like this but is lengthier, navbarLogo.href is the example:
const displayHeader = () => {
const navbar = document.createElement('div');
navbar.classList.add('navbar');
centeredContainer.appendChild(navbar);
const navbarLogo = document.createElement('a');
navbarLogo.classList.add('navbar-logo');
navbarLogo.href = "/src/index.html";
navbar.appendChild(navbarLogo);
}
export default displayHeader;
Do you know how to handles these types of path problems?

Getting path to file in published webcomponent

I have a webcomponent where I need to add a link tag to the head and set the href equal to a folder inside that node module.
Right now I'm in the building phase of this component where my structure look like this:
So I need to add the fontawsome.css script to the head of my page. I've created the following script:
constructor() {
super();
if (!this.isFontAwesomeLoaded()) {
this.iclass = '';
const fontEl = document.createElement('link');
fontEl.rel = 'stylesheet';
fontEl.href = "./fontawesome/css/all.css";
document.head.appendChild(fontEl);
}
}
Now there is a problem with this the path ./fontawesome/css/all.css won't work when it hits the head tag because the index.html file that attempts to load it doesn't have the folder in its project. instead when it hits product it needs to find the absolute path to my module and then to the fontawesome folder.
My question is how can I get that path?
There is a lot of things that should be avoided:
External dependencies from within web-component is a bad idea, especially something big like fontawesome. You said that you try to avoid coupling, but actually you introduce it with such dependency.
Web-components rarely should be used without shadow-dom (IMHO), by accepting fontawesome you basically ignore that functionality of web-components.
There are a couple of ways you could handle such scenario:
extract what you need from fontawesome's all.css into your web-component.
state in your component's docs that it depends on fontawesome and that the client should provide it on their side
use CDN (really bad decision, avoid this):
constructor() {
super();
if (!this.isFontAwesomeLoaded()) {
this.iclass = '';
const fontEl = document.createElement('link');
fontEl.rel = 'stylesheet';
fontEl.href = "https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css";
document.head.appendChild(fontEl);
}
}

Loading chunks from dynamic imports though CDN URL like other assets

I have a CDN pointing to my base domain, there is 1:1 mapping basically. I'm trying to build my bundle on the server, and I want to load it using CDN URL. What I want to have after npm run build is:
public/
css/
app.css
js/
index.js
1.js.gz
1.js
2.js.gz
2.js
And then my CDN will reflect that, so I want these resources to be loaded like this:
https://mycdn.com/public/js/index.js
https://mycdn.com/public/css/app.css
My current webpack.mix.js config:
mix
.sass('resources/sass/app.css', 'public/css')
.js('resources/js/index.js', 'public/js')
It generates all files in the proper location, which is good. Then I include them in my index.blade.php:
<script src="{{ elixirCDN('/js/index.js') }}"></script>
elixirCDN is my custom function:
function elixirCDN($file)
{
$cdn = '';
if(config('system.cdn_url'))
{
$cdn = config('system.cdn_url');
}
return $cdn . elixir($file);
}
It basically prepends filename with CDN url, so it all works fine.
The problem begins when I use dynamic imports, like this:
const Home = () => import("./Home")
The ideal situation would be that it also loads with the CDN:
https://mycdn.com/public/js/1.js
but instead, it doesn't, it loads with a relative path and my base domain:
https://mybasedomain.com/public/js/1.js
Obviously, because it's dynamic. How can I make my chunks to be loaded from the CDN as well?
I've tried to set publicPath as my CDN url, but it doesn't have any effect. I've also tried setPublicPath() but it's the same.
Hi this is not the definitive answer but a step in the right direction. I got into this issue because my conditional import broke after updating all the webpack and babel packages.
Before the dynamic import you need to set the temporary public path for webpack to the location of the chunck which webpack needs to import dynamically
__webpack_public_path__ = 'https://cdn.dev.acsi.eu/eurocampings/assets/dev/dist/';
Than the import works
import(/* webpackChunkName: "state" */ './modules/BookingState/State')
.then(({createState}) => {
createState();
this.renderEurocampingsWebsite(window);
});
For me the dynamic import works, however it seems that the conditional import before, all the package updates, was working in without async behavior...
Just found out that Webpack has more magical comments, which can make the code behave procedural, at the cost of having both modules imported for the conditional import. This might also be helpful
import(
/* webpackChunkName: "state" */
/* webpackMode: "eager" */
/* webpackPreload: true */
'./modules/BookingState/State'
)
.then...
I had a similar problem, where my main script was loaded into another page, and when loading chunks it tried loading them from the root url instead of the cdn.
Using the answer above, I came to the following solution:
in root imported file
export function setWebpackToLoadChunksFromScriptUrl() {
const scriptPath: string = (document.currentScript as any || {}).src;
const loadPath = scriptPath ? scriptPath.substring(0, scriptPath.lastIndexOf('/')) : '';
if (loadPath) {
__webpack_public_path__ = loadPath;
}
}
setWebpackToLoadChunksFromScriptUrl();
export async function loadApplication(elementId: string) {
const { loadApplicationOnHtmlElement } = (await import('./loaded-app'));
loadApplicationOnHtmlElement((elementId));
}

How to load external library from local path

I have a code importing list of external urls(http//....js)
for (const id in urls) {
let tag = document.createElement('script');
tag.async = false;
tag.src = urls[id];
let body = document.getElementsByTagName('body')[0];
body.appendChild(tag);
}
But for security reasons, I copy&pasted the js file to local file, but dont know how to import it like I used to do.
Simply
import "../lib/asmcrypto.js";
gives me thousands of errors saying 'Expected an assignment or function call and instead saw an expression'.
Any help is appreciated!
If you're inside a browser, the most common way of loading your JS resource would be:
<script src="/lib/asmcrypto.js"></script>
If you're using Webpack at some level, like when you're project is on React or Angular or ...
import crypto from "../lib/asmcrypto.js";
It's important to understand that, it's usually the bundler e.g. Webpack that takes care of import and export in your project.

How to import a module from the static using dynamic import of es6?

I'm trying to add dynamic import into my code to have a better performance on the client-side. So I have a webpack config where is bundling js files. On SFCC the bundled files are in the static folder where the path to that files is something like this: /en/v1569517927607/js/app.js)
I have a function where I'm using dynamic import of es6 to call a module when the user clicks on a button. The problem is that when we call for that module, the browser doesn't find it because the path is wrong.
/en/lazyLoad.js net::ERR_ABORTED 404 (Not Found)
This is normal because the file is on /en/v1569517927607/js/lazyLoad.js.
There is a way to get it from the right path? Here is my code.
window.onload = () => {
const lazyAlertBtn = document.querySelector("#lazyLoad");
lazyAlertBtn.addEventListener("click", () => {
import(/* webpackChunkName: "lazyLoad" */ '../modules/lazyLoad').then(module => {
module.lazyLoad();
});
});
};
I had the same problem and solved it using the Merchant Tools > SEO > Dynamic Mapping module in Business Manager.
There you can use a rule like the following to redirect the request to the static folder:
**/*.bundle.js i s,,,,,/js/{0}.bundle.js
All my chunk files are named with the <module>.bundle pattern.
Here you can find more info :
https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/content/b2c_commerce/topics/search_engine_optimization/b2c_dynamic_mappings.html
Hope this helps.
I believe you'll likely need to do some path.resolve() magic in either your import statement or your webpack.config.js file as is shown in the accepted answer to this question: Set correct path to lazy-load component using Webpack - ES6
We did it in a different way. That required two steps
From within the template file add a script tag that creates a global variable for the static path. Something like
// inside .isml template
<script>
// help webpack know about the path of js scripts -> used for lazy loading
window.__staticPath__ = "${URLUtils.httpsStatic('/')}";
</script>
Then you need to instruct webpack to know where to find chunks by changing __webpack_public_path__ at runtime
// somewhere in your main .js file
// eslint-disable-next-line
__webpack_public_path__ = window.__staticPath__ + 'js/';
Optional step:
You might also want to remove code version from your __staticPath__ using replace (at least we had to do that)
__webpack_public_path__ = window.__staticPath__.replace('{YOUR_CODE_VERSION_GOES_HERE}', '') + 'js/';

Categories

Resources