Include JSON files into React build - javascript

I know this question maybe exist in stack overflow but I didn't get any good answers, and I hope in 2020 there is better solution.
In my react app I have a config JSON file, it contains information like the title, languages to the website etc..
and this file is located in 'src' directory
{
"headers":{
"title":"chat ",
"keys":"chat,asd ,
"description":" website"
},
"languages":{
"ru":"russian",
"ar":"arabic",
"en":"English"
},
"defaultLanguage":"ru",
"colors":{
"mainColor":"red",
"primary":"green",
"chatBackGround":"white"
}
}
I want to make my website easy to edit after publishing it, but after I build my app, I can't find that settings.json file there in build directory.
I find out that files in public directory actually get included to build folder, I tried to put my settings.JSON in public,
but react won't let me import anything outside of src directory
I found other solutions like this one but didn't work
https://github.com/facebook/create-react-app/issues/5378
Also I tried to create in index.html a global var like (window.JSON_DATA={}), and attach a JS object to it and import it to App.js, but still didn't work.
How can I make a settings JSON file, and have the ability to edit it after publishing the app?

Add your settings.json to the public folder. React will copy the file to the root of build. Then load it with fetch where you need it to be used. For example if you need to load setting.json to the App.js then do the next:
function App() {
const [state, setState] = useState({settings: null});
useEffect(()=>{
fetch('settings.json').then(response => {
response.json().then(settings => {
// instead of setting state you can use it any other way
setState({settings: settings});
})
})
})
}
If you use class-components then do the same in componentDidMount:
class CustomComponent extends React.Component {
constructor(props) {
super(props);
this.state = {settings: null};
}
componentDidMount() {
fetch('settings.json').then(response => {
response.json().then(settings => {
this.setState({settings: settings});
})
})
}
}
Then you can use it in render (or any other places of your component):
function App() {
...
return (
{this.state.settings && this.state.settings.value}
)
}

The easiest way would be to require() the file on the server during server side rendering of the html page and then inline the json in the html payload in a global var like you mentioned window.JSON_DATA={}. Then in your js code you can just reference that global var instead of trying to use import.
Of course this approach would require you to restart your server every time you make a change to the json file, so that it get's picked up. If that is not an option then you'll need to make an api call on the server instead of using require().

You may want to look at using npm react-scripts (https://www.npmjs.com/package/react-scripts) to produce your react application and build. This will package will create a template that you can put your existing code into and then give you a pre-configure build option that you can modify if you would like. The pre-configured build option will package your .json files as well. Check out their getting started section (https://create-react-app.dev/docs/getting-started/)
If you don't want to go that route, and are just looking for quick fix, then I would suggest change your json files to a JS file, export the JS object and import it in the files you need it since you seem to be able to do that.
//src/sampledata.js
module.exports = {
sample: 'data'
}
//src/example.jsx (this can also be .js)
const sampledata = require('./sampledata');
console.log(sampledata.sample); // 'data'

you can use 'Fetch Data from a JSON File'
according to link
https://www.pluralsight.com/guides/fetch-data-from-a-json-file-in-a-react-app
example

Related

laravel 8 include certain javascrip file into other js file

I have two files, one is my main js file called app.js and I have a file where I store all my js functions, called functions.js. As you can see on the image below.
But I want to include the functions.js file into the app.js file. So I googled on how to do it and this is what people said:
But my npm run dev says the file doesn't exist. But the path is correct. What am I doing wrong here, is there a other way to do it?
You can simply just create the file wherever you want to create it, and then export some properties or methods, and then import them in your app.js file, or in whatever file you need. Something like this :
//new_file.js
export const jokes = function() {
return ['funny', 'not really funny', 'boring']
}
export const heading = 'some global heading to be reused.'
And in your app.js file :
import { jokes, heading } from 'new_file.js'//specify actual path here .
console.log(jokes) // ['funny', 'not really funny', 'boring']
console.log(heading)//some global heading to be reused.
This tutorial might be helpful too .
http://www.2ality.com/2014/09/es6-modules-final.html

How to add custom scripts bundle in NextJS

I have some legacy custom javascripts that I need to bundle and put them in _document.js as a link. The filename should include a hash.
What would be the best way to accomplish this?
I tried webpack configs regarding entry/output but they break NextJs build.
The problem is that we use things like window, document, etc that do crash in server side.
Ideally what is needed is to inject this into a tag, as compiled / babelified javascript code.
What I tried is
Webpack HTML Plugin plus other plugins like InlineChunk or
InlineSource plugins. They didn't work because they generate code in
an index.html that is not used by NextJS.
Using Raw Loader to get the file content. Doesn't work because it is
not babelified.
Adding a custom entry to the Webpack config, like scripts:
'path/to/my-entry.js'. Didn't work because it adds a hash name to the
file and I have no way of knowing it.
Adding a custom entry into the NextJs polyfills. I thought it made
sense, but the polyfill tag has a nomodule which prevents its code to
run on new browsers.
Another options is to add the javascript code as a string, and then using __dangerouslySetInnerHtml but the problem is that I lose linter and babel abilities there.
I tried adding it as a page, but crashes for local development and even on build
webpack.config.js
module.exports = (nextConfig = {}) =>
Object.assign({}, nextConfig, {
webpack(config, options) {
const nextJsEntries = config.entry;
config.entry = async () => {
const entries = await nextJsEntries();
entries['pages/rscripts'] = 'test/test.js';
return entries;
};
...
Then in _document.js
<script src={`${publicRuntimeConfig.ASSET_PREFIX}/_next/${this.props.buildManifest.pages['/rscripts'][2]}`} />
You can just import js file like import 'path/to/js_file' in your _app.js/app.tsx file
import "../styles/globals.css"
import "../js/test"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
This one works fine for me
I wanted to add another answer here as I came across this and I believe some things have changed in Next JS. Next now has this script component that you can use to load external scripts or dangerously set a script.
The Next.js Script component, next/script, is an extension of the HTML
element. It enables developers to set the loading priority of
third-party scripts anywhere in their application, outside next/head,
saving developer time while improving loading performance.
The cool thing is you can put them into whatever pages you want, maybe you have a script you want on a homepage, but not other pages, and Next will extract them and place them on the page based on the strategy you select. There are a few gotchas, can't load in the head, beforeInteractive is a little finicky, so I would read the link above and the actual API reference before making any choices.
import { useEffect } from 'react';
import Script from 'next/script';
function thirdPartyScript() {
useEffect(() => {
// just for fun. This actually fires
// before the onLoad callback
}, []);
return (
<Script
id="test-script"
strategy="afterInteractive"
src="/public/pages/scripts/test.js"
onLoad={() => {
console.log('Onload fires as you would expect');
}}
/>
);
}

Implement with cypress with page object model

I'm trying to create cypress test project which support page object model.
I have created a new folder 'pageobject' at ../integration and there I have implemented LoginPageAdminPortal.js file as a page object class.
Code is like below,
export class LoginPageAdminPortal
{
visitLoginPageAdminPortal()
{
cy.visit (cypress.env('ADMIN_PORTAL_LOGIN_URL'))
}
loginAdminPortal()
{
cy.get('input[name=usernameUserInput]').type(cypress.env('ADMIN_USER_NAME'))
cy. get('input[name=password]').type(cypress.env('ADMIN_USER_PASSWORD'))
cy.contains('Continue').click()
return this
}
}
Then I wrote a test script for user login and the test sript locate at integration folder.
import {LoginPageAdminPortal} from '/pageobject/'
describe('Admin portal login with username and password', () => {
it ('Visit to the admil poratl login page', () => {
const loginPage = new LoginPageAdminPortal()
loginPage.visitLoginPageAdminPortal()
})
})
But at the compilation time I'm getting error like,
Error: Cannot find module '../pageobject/' from ' /home/achini/projects/cloudtest/cypress/cypress-iam-ui-test/iam-cypress-ui-test/cypress/integration'
Do I have to configure the pageobject module some other file. Any idea to solve this and successfully implement cypress with page object model.
folder structure
reference :
https://www.youtube.com/watch?v=5ifXs65O36k
https://www.youtube.com/watch?v=hMiBundGmNA
Imports are relative to the test which is in the integration folder, so you want
import { LoginPageAdminPortal } from './pageobject/LoginPageAdminPortal';
Please check out these two repositories where I implemented an example of the PO pattern. In one repository, I did it with TypeScript, and in the other one, I did it with JavaScript.
https://github.com/antonyfuentes/cypress-typescript-page-objects
https://github.com/antonyfuentes/cypress-javascript-page-objects
I think a good practice is to keep the integration folder only with your tests files. You can move the pageobject folder under support and use
import LoginPageAdminPortal from '../../support/PageObjects/LoginPageAdminPortal'in order to access the file.

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/';

meteor: import directory - modular import of methods which are needed

I'm migrating my meteor application to the import-function of meteor 1.3.
But I think this is not quite the best way it should be done. Isn't it possible to load/import just the method which is really needed?
I mean, right now just all methods are loaded by importing the the methods.js. But I would like to do that in a modular way. So if the form .fomNewElement is used in the app, the method insertArticle will be imported and so on. Not just loading everything...
Below you can see my folder structure for /imports and some content of the files. Is there anything more I could improve in the structure itself?
Also it would be great if the import would depend on user roles. Is this possible?
imports/api/article/client/article.js
import { Articles } from '../';
import { insertArticle, updateArticle } from '../methods.js';
Template.Articles.helpers({
// some helpers
});
Template.Artilces.onCreated(function() {
// some code
});
Template.Artilces.onRendered(function() {
// some code
});
Template.Articles.events({
'submit .formNewElement': function(event) {
event.preventDefault();
var title = event.target.title.value.trim();
insertArticle.call({
title: title
});
},
'click .anything': function() {}
});
As you can see, I put into that js-file all helpers, events and onCreated/onRendered code. Hope this is 'correct'... Please give me some hint, if this isn't very smart.
imports/api/article/index.js
export const Articles = new Mongo.Collection('articles');
imports/api/article/methods.js
import { Articles } from './';
export const insertArticle = new ValidatedMethod({
name: 'article.insert',
validate: new SimpleSchema({
title: { type: String }
}).validator(),
run( document ) {
Articles.insert( document );
}
});
export const updateArticle = new ValidatedMethod({
name: 'article.update',
validate: new SimpleSchema({
_id: { type: String },
'update.title': { type: String }
}).validator(),
run( { _id, update } ) {
Articles.update( _id, { $set: update } );
}
});
And the other files:
imports/startup/client/index.js
import '../../api/redactor-article/client';
imports/startup/server/index.js
import '../../api/redactor-article/server/publications.js';
import '../../api/redactor-article/methods.js';
imports/api/article/client/index.js
import './article.html';
import './article.sass';
import './article.js';
Filestructure
/imports
/api
/article
/client
article.html
article.js
article.sass
index.js
/server
publications.js
index.js
methods.js
Update
Maybe it would be a better way to structure an import module like this:
imports/
api/
articles/
publication.js
methods.js
collection.js
ui/
articles/
article.html
article.css
article.js // contains helpers, events and onCreated/onRendered
Then I have to import the files in startup/client (-> all ui files of this module AND all api files) and startup/server (-> just all api files)...
Right?
A few points:
You've put everything under imports/api. That directory is designed for collections, methods, helpers, 'business logic' and public API (e.g. if you expose a REST API, you'd do it from within that directory). Use imports/ui for your templates (including their styles and associated .js files).
You don't need to differentiate between client and server directories within imports. Just import the files you need from the respective main entry points (i.e. client/main.js and server/main.js). This point is a little more complex than I suggest here, see the link to 'structure' in the Meteor Guide, below.
index.js doesn't seem like a logical place to put your Articles collection. I'd make a file at /imports/api/articles/articles.js for it. See http://guide.meteor.com/structure.html for a good overview about where to put things and why.
Also, in the interests of following best-practices, use a default export for your Articles collection: http://guide.meteor.com/code-style.html#collections
To answer your question about how much of the file is exported (i.e. which functions), there's not much you can do about everything being loaded. The bundler needs to read the entire JS file anyway (imagine you exported an object and then changed it further down in the same file– not the best practice, but possible). If you're not using a function though, by all means, don't import it! And you can always split up your methods into seperate files if they get unmanageable.
Regarding your question about only importing bits for certain user roles: always avoid using imports or other types of obfuscation for security. The ideal way to do security on Meteor is to assume ANYTHING is accessible on the client (it pretty much is) and code your server-side code accordingly. That means, if you have an admin area, assume that anyone can access it. You can do checks in server methods and publications for this.userId and do a database lookup there to ensure the user has the correct privileges. Again, the guide has more info about this: http://guide.meteor.com/security.html
A final note about imports/exports: the idea behind them is not to reduce code size, but to provide a graph of what is actually being used (and leaving out the files that aren't) to make hot code reloading faster for a better development experience. They also make for cleaner application code that is easier to understand, because you don't have random magical globals swimming around that could have come from anywhere, and help to keep logically distinct pieces of code separate.
Best of luck :)

Categories

Resources