Bundle external JavaScript(from a cdn) into a React component - javascript

What options are there to bundle an external javascript sdk into a React Component?
I have tried including the javascript in the index.html and referring to it through window.xyz . It works well but I can't do a production build since the javascript is not packaged in this way.
Is there a way to simply import a javascript file into the React Component definition?
PS: React Newbie here !

If you want the script to be bundled in the build, you have 2 options:
1. If the external file is a module, I would approach it as follows:
Download the external JS file and save it somewhere in the project. For example, save it to /utils folder.
Just reference it and use it in the components: import { test } from '/utils/external'
2. If it's not a module:
The same as above - save the file to your project.
The difference is that you have to configure your module bundler to export the globals. This process is called Shimming and here's how to do it with Webpack.
The same as step 2 - import { test } from '/utils/external'
* In both scenarios I assume it's a standalone external file, not being hosted somewhere as a package (npm / bower / etc.). If it's a package, instead of downloading it manually, you should use a package manager.
If you want to load it async (but not bundled):
Follow the #Paras answer, where he suggests for using a library for script async lazy loading.

To load external scripts from a CDN, a good option is to use the react-async-script-loader library. Not only can it load external JS files asynchronously, but it also loads on demand, i.e., lazy loading and supports both parallel and sequential loading.
It allows you to decorate your component using an HOC like so:
export default scriptLoader(
[
'https://cdnjs.cloudflare.com/somelibrary1.min.js',
'https://cdnjs.cloudflare.com/somelibrary2.min.js'
]
)(YourComponent)

Actually you should know about the entire approach then see the codes.
You must make a separate folder for your alternative cdn JavaScript files which they are out of files that webpack build them. Then paste these files into this folder and after all import them as externals into webpack configuration.
Then config them as vendor files, and absolutely output file name should make dynamically, so the webpack build its bundle and then copy your JavaScript files into dist folder. follow below:
// webpack.configuration.js
~~~
module.exports = {
~~~
externals: {
cdnFileOne: `${srcRoot}/outFiles/cdnFile1.js`,
cdnFileTwo: `${srcRoot}/outFiles/cdnFile2.js`,
},
~~~
};
Sounds good, now you have external names for JavaScript files and import it into webpack configuration as a externals config.
Now you should put them in entry to import them as separate files:
// webpack.configuration.js
~~~
module.exports = {
~~~
entry: {
cdnFiles: ['cdnFileOne', 'cdnFileTwo'], <-- cdn files
app: `${srcRoot}/app/index.js`, // <-- its your own codes
},
output: {
path: '/dist',
filename: '[name].js' // <== dynamically make your JavaScript files,
// so, in dist folder you can see app.js and
// cdnFiles.js file
}
~~~
};
Surly, you must add bundles to your HTML template:
~~~
res.status(200).send(`
<!doctype html>
<html lang="en">
<head>
<meta charSet="utf-8" />
${styles}
${title}
</head>
<body>
<div id="root">${ssrHTML}</div>
<script src="app.js" defer></script>
<script src="cdnFiles.js" defer></script>
</body>
</html>
`);
~~~

try something like this:
componentDidMount () {
const script = document.createElement("script");
script.src = "https://cdnjs.cloudflare.com/somelibrary1.min.js";
script.async = true;
document.body.appendChild(script2);
}

Related

Webpack - Change 'src' path of javascript files in index.html

I am facing an issue after building my strapi application (using webpack).
After i executed yarn build, my index.html imports javascript files using the <script> tag.
The issue comes here, in my build folder, there are all of my files (images, js files etc...), and 0 subfolder.
But inside my index.html, it imports from an invalid path:
<script src="admin/file.js"></script>
I want to change this src with Webpack to look like that :
<script src="./file.js"></script>
Anybody got a solution ?
Thank you.
Finally, i found the fix.
I am using Strapi for this web app.
Strapi automatically fills webpack with publicPath "/admin/".
However, webpack doesn't understand and put every files (js, img, html) in the same directory, at the same level (no subfolders).
So inside src/admin/, remove the word "example" from the file name "webpack.config.example.js"
Open this file and insert this code
'use strict';
module.exports = (config, _webpack) => {
config = {
...config,
output: { ...config.output, publicPath: './'}
}
return config;
};

Vue - Remove specific JavaScript files for production mode

I have lots of .js files to import in Vue components in my project. Some of these JavaScript files are meant to be used in development mode and they won't be included in production but I am not allowed to delete these files in project. For example;
There are two JavaScript files called authDev.js and authProd.js. Their usage is basically the same but their content are different from each other. Inside of these JavaScript files there are functions and I export them to be able to import in several Vue components.
The first question, If I dynamically export or import them, will webpack include these files when I run npm run build? In other words, let's say I created a JavaScript file but I didn't export it, so I didn't import it to anywhere either. Does webpack understand that this JavaScript file is not used in anywhere of these Vue project and discard it when it builds my project to production? Or does it include every single file that existed in the project?
The second question, is there a way to tell the webpack that those JavaScript files will not be included in dist folder these will... I mean, can I specify files for development and production?
First I thought I could import or export them based on a condition but when I try to put my imports in if statements, it gives me an error and says "imports must be at the top level". So I tried to export them dynamically but couldn't do it either.
Then I try to remove specific blocks of codes in files. There are packages and plugins to remove every console outputs from Vue projects but I couldn't find anything to remove or discard specific lines of codes.
At last, I decided to took a way to include and exclude specific files. Is there a way to do it? If it is, how do I do that? Thanks in advance.
THE SOLUTION (EDITED)
For a quick test, I created two .js files called auth-development.js and auth-production.js in src/assets/js/filename.js location. Here are the contents of them;
auth-production.js
export const auth = {
authLink: "http://production.authlink/something/v1/",
authText: "Production Mode"
}
auth-development.js
export const auth = {
authLink: "http://localhost:8080/something/v1/",
authText: "Development Mode"
}
Then I modified my webpack config which is in the vue.config.js file;
const path = require('path');
module.exports = {
configureWebpack: {
resolve: {
alias: {
'conditionalAuth': path.resolve(__dirname, `src/assets/js/auth-${process.env.NODE_ENV}.js`)
}
}
}
}
Vue was giving "path is undefined" error, I added the top part of the code to handle that error. I used process.env.NODE_ENV to get the words development and production to add the end of my javascript files so that I can define their path.
Then I dynamically imported this conditionalAuth to a test component called "HelloWorld" as follows;
<script>
import * as auth from 'conditionalAuth';
export default {
name: 'HelloWorld',
data(){
return {
auth: auth
}
}
}
</script>
And I used them like this;
<template>
<div>
<p>You are in the {{ auth.auth.authText}}</p>
<p>{{ auth.auth.authLink }}</p>
</div>
</template>
In this way when I npm run serve it imports auth-development.js but if I npm run build and try the index.html in the dist folder on a live server, it only imports the auth-production.js.
At last, when I check the final build, auth-development.js is not built for my dist version of the project. It only imports the production javascript file in the chunk.
Assuming the file names are: auth-development.js and auth-production.js, you can use webpack alias to import file according to environment.
resolve: {
alias: {
'conditionalAuth': path.resolve(__dirname, `path/to/js/auth-${process.env.NODE_ENV}.js`)
},
extensions: ['.js', '.vue', '.json']
}
then you should be able to import the desired file like:
import * as auth from 'conditionalAuth';

Adding service workers in Aurelia

To make my aurelia app a proper PWA, that I have created using aurelia cli, I need to register a service worker.
There is already a similar unanswered question or few discussions and forum posts on the web available regarding the subject matter but I couldn't find anything concrete to help me get started.
I am thinking of three possible ways to handle this
option[1] - use index.html page and register a service worer inside a script tag outside the scope of aurelia app.
// service worker in index.html file
<!DOCTYPE html>
<html>
<head>
</head>
<body aurelia-app="main">
<script type="text/javascript">
... my service worker code here ...
</script>
</body>
</html>
option[2] - inside aurelia main.js/main.ts
// inside aurelia main.js/main.ts file
export function configure(aurelia) {
... rest of the conf ...
registerServiceWorker();
return aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
}
option [3] - app.js file
// inside app.js file constructor
export class App {
constructor() {
this.registerServiceWorker();
}
What would be the proper/right way to handle this task? As I am using webpack, would it need more configuration to make the service worker play nice with webpack and aurelia?
If using WorkBox is the only way forward, I can live with that too but to keep things simple I would prefer to use vanilla service workers directly in aurelia.
This is how I made it to work.
1- insatll workbox plugin
yarn add workbox-webpack-plugin
2- configure webpack
//webpack.config.js
// add plugin somewhere in the top section
const workboxPlugin = require('workbox-webpack-plugin');
//inside plugins section
plugins: [
// somewhere in the bottom is OK
new workboxPlugin.GenerateSW({
swDest: 'sw.js', // name of your service worker file
clientsClaim: true,
skipWaiting: true
}),
3- put your sw.js file in static dir. It will be moved to the dist folder on build.
4- if it is a complete PWA, add manifest.json file too in the static dir. you can get a sample manifest.json file from google developr site.
5- add service worker init script into the index file
// index.html or index.ejs file
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) { return registration.update(); })
.catch(error => console.log(error));
}
</script>
run and hopefully you should get the serveiceworker installed and running.
P.S. is this the proper way to do it? I have no idea, but for now it is working for me.

bundling multiple js files

in react using webpack every js files is bundle into a single bundle.js , for my normal html , css, js application for example , i am having 6 libraries. for an example consider
i am using jquery and bootstrap min versions. so if i reference two files the request will be two. so how can i make it into a single file. So there will be a single request.
like when i checked the file size is about in kb's and the request is processed within less that 1 or 2 seconds , like the chrome dev tools shows the time for to load also it parrallely loads the two files.
But how can i bundle the two librarys using webpack and get a single file that i can refer in my application.
i am a beginner to webpack
You need to import them in your entry point file and Webpack will handle the bundling. As you have worked with React, I assume you have basic command line skills.
You can read the Getting Started guide which bundles Lodash like how you are trying to bundle jQuery and Bootstrap.
First of install, ensure that you are installing jQuery, Bootstrap, and any other libraries using npm (or yarn, if you prefer):
# Install Webpack as a dev dependency
npm install webpack webpack-cli --save-dev
# Install dependencies (I've added Popper.js as Bootstrap requires it)
npm install jquery bootstrap popper.js
Create a folder called src and a file inside there called index.js. This is your entry point and Webpack will look for this file unless configured differently. Import the libraries like this:
import $ from 'jquery'
import 'bootstrap'
// Do something with jQuery
$(document).ready(() => console.log('Hello world!'))
Then run Webpack using npx:
npx webpack
A file named main.js should be created in a folder called dist that contains the bundled code. This is your output file. You can use a <script> tag in your HTML file to load this JavaScript:
<!-- assuming your index.html is in the dist folder -->
<script src='main.js'></script>
Once you get here, you can explore more advanced things like importing Bootstrap components individually, minifying code, multiple bundles, transpiling TypeScript, etc.
You will likely need to add a Webpack configuration file very soon as there is only so much that can be done using zero-config mode.
Good practice is to keep two sepearate bundles for the application logic and external libraries and in webpack this can be achieved by the following code,
app.js - appliation index file,
vendors.js - import all external libraries in this file
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
To get a single file, import vendors.js file inside app.js file and give entry key in webpack as
entry: './src/app.js'
Let us assume that you have the files in src directory. You can merge multiple files by specifying them in webpack.config.js to have a single named file as an output. I hope this is what you are looking for.
const path = require('path');
module.exports = {
entry: {
'bundle.js': [
path.resolve(__dirname, 'src/file1.js'),
path.resolve(__dirname, 'src/file2.js')
]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [{
exclude: /node_modules/
}]
}
};
As above, the two files "file1.js" and "file2.js" will be combined into a single file "bundle.js" and stored in "dist" directory.
You can also exclude node_modules by specifying a rule in module object of webpack configuration.

Webpack - CommonsChunkPlugin (lib building), common.js not loading in parent app

I am creating the UI component library in React...
My Webpack config have multiple entry points which result in multiple bundles eg:
Am using CommonsChunkPlugin which generates the common.js, which is shared code between other bundles.
In parent app (React app in which I want to consume UI lib) I do:
import { Button } from 'ui-library/lib/Button';
But this Results in:
webpackJsonp is not defined
Which means that common.js is not loaded. Here is my webpack plugins property value:
Am I missing something? IS common.js supposed to be loaded manually in the parent project? I expeted that importing the cmp is all which should be required, but maybe I am wrong, or I just missed something in the config...
Yes, you should import common.js manually, as stated in the documentation :
You must load the generated chunk before the entry point:
<script src="commons.js" charset="utf-8"></script>
<script src="entry.bundle.js" charset="utf-8"></script>
Source : https://webpack.js.org/plugins/commons-chunk-plugin/

Categories