So I'm trying to import a different javascript file based on a boolean in my react application.
When I'm running it in dev mode I want to import my testProxy.js file which just returns back json data.
When i'm running the application in production I want to use prodProxy.js where it connects to my production application via ajax and returns back results, etc.
I have achieved this with webpack by doing:
new webpack.ProvidePlugin({
api: isDevBuild ? "./dev/api" : "./prod/api"
}),.
And then in my file I just declare the api.
declare var api: any (using typescript)
I am not really liking this and I don't know another way.
What I want is what's below
pseudo code below:
let _api = isDev ? import('devApi') : import('prodApi');
let someObject = new MyClass(_api);
Tried this and it fails.
let _api = isDev ? import('devApi') : import('prodApi');
let someObject = new MyClass(_api);
this is not possibe:
You must import all ES6 modules at the top level of your JavaScript files.
You can’t import an ES6 module based on a conditional.
you can do:
let _api = isDev ? require('./devApi') : require('./prod/api');
let someObject = new MyClass(_api);
I don't know what isDev is referring to. Asuming you have some node/browser setup, and isDev is based on a environment variable passed by process.env.DEVELOPMENT, this will not be available on the client.
You would need to use the webpack evironment plugin: https://webpack.js.org/plugins/environment-plugin/ and add the env variable to it, so u can access it from the client.
sidenote: added on build time, not on run time.
Hope this helps.
Related
Exports.local Node js sample code
I am using passport-local-mongoose in my node js Application and I come across exports.local for passport authentication. I couldn't understand it function. Please check the image above
In your case here there is nothing special about local keyword, it is just the name of the variable that is used to export the passport local authentication strategy configuration, so you can call it in other files using require, so here in your example, you have this logic written in authenticate.js, so to use it in any other file you will have to call it using the following:
const { local } = require('./authenticate'); // identify the right path to authenticate.js
enter code here
The CommonJS (CJS) format is used in Node.js and uses require and module.exports to define dependencies and modules. The npm ecosystem is built upon this format. In your case exports.local creates a new module and export it for the use elsewhere.
Example
user.js
const getName = () => {
return 'Jim';
};
exports.getName = getName;
index.js
const user = require('./user');
console.log(`User: ${user.getName()}`);
Output
User: Jim
I'm developing a package for the Atom text editor, and in order for that package to work, it reads some JSON files that act as a simple database. Also, those JSON files should be periodically updated with data obtained from a public spreadsheet, thus they must be written to.
The problem, however, is that using fs.writeFile, paths are relative to the user's home folder, not to the package folder. While I could use a path like .atom/packages/package-name/file.json, to my limited knowledge of Atom packages, that does not feel like a good practice (or is it?).
Are there any other solutions?
I don't see a problem using relative paths in your script like so:
const pathToJson = path.resolve(__dirname, 'file.json`);
// next: write data to JSON
However, if you really want to use absolute paths, there are several options.
Atom API
You can use the Atom API inside your package, which exposes the resolvePackagePath() method:
const packagePath = atom.packages.resolvePackagePath('name-of-your-package');
const pathToJson = path.resolve(packagePath, 'file.json`);
// next: write data to JSON
You can combine this with the following snippet to retrieve the package name from the manifest:
const { name } = require('./package.json');
3rd party package
The atom-read-manifest package allows you to do the same without having to specify the name of your package – but that's a question of personal taste, I guess.
const { readManifest } = require('atom-read-manifest');
// or use readManifestSync
(async () => {
const { name } = await readManifest();
const packagePath = atom.packages.resolvePackagePath(name);
const pathToJson = path.resolve(packagePath, 'file.json`);
// next: write data to JSON
})();
One final note: If your package is writing the data to the JSON, there are probably better ways to achieve the same. You need to consider that updating the package will overwrite your old file.json. Personally, I'd prefer to write the data to Atom's localStorage (or IndexedDB). If you prefer writing the data to a JSON file, then you should probably save it to .atom/storage instead.
I'm trying to access the strftime JS library in my Rails application. I've followed the instructions on how to add it using yarn add and I've added a debugger statement in one of my react components so I can try and access it through the console. strftime is not defined and the instructions say this about requiring it:
var strftime = require('strftime') // not required in browsers
console.log(strftime('%B %d, %Y %H:%M:%S')) // => April 28, 2011 18:21:08
console.log(strftime('%F %T', new Date(1307472705067))) // => 2011-06-07 18:51:45
I believe require is a node.js thing because you can't "require" code in the browser. It states that its not needed in the browser but the instructions also say to add it as a <script> tag but if I have the webpacker gem, I should be able to just do something like:
import strftime from 'strftime'
in my application.js file right?
What is required to get access to a library from node_modules in my Rails app?
Edit:
Some context: This is an existing application running Rails 5.2.3 which is currently being migrated from sprockets/asset pipeline to React components with Webpack(er).
I've updated my environment.js file using the answer from #thanhnha1103.
If I open my app in Chrome for example and go to the console and type strftime it says strftime is not defined. However, if I add a debugger instruction in my application.js file just after import strftime from 'strftime' I get access to two objects called strftime__WEBPACK_IMPORTED_MODULE_0__ and strftime__WEBPACK_IMPORTED_MODULE_0___default.
Now if I do this in console while the JS has stopped because of debugger:
strftime = strftime__WEBPACK_IMPORTED_MODULE_0__
I have access to a function called strftime which is my intended purpose. (I also have to import strftime in my react component to get access to this but that's probably as intended. Any ideas about how to make this work out of the box without doing this in my application.js file?:
import strftime from 'strftime'
strftime = strftime__WEBPACK_IMPORTED_MODULE_0__
debugger // obviously I'll remove this later but this is for testing purposes.
console.log('Hello World from Webpacker')
// Support component names relative to this directory:
var componentRequireContext = require.context("components", true);
var ReactRailsUJS = require("react_ujs");
ReactRailsUJS.useContext(componentRequireContext);
You should try this in your config files:
// config/webpack/environment.js
const webpack = require('webpack');
const {environment} = require('#rails/webpacker');
environment.plugins.append(
'ProvidePlugin-Strftime', // arbitrary name
new webpack.ProvidePlugin({
strftime: 'strftime'
}),
);
module.exports = environment;
I have created a logging utility function that I plan to use on 99% of components in my site. I am wondering if it is possible to access this file without having to write "import { logger } from 'utils/logging';" for every React component? Sort of like an auto import?
I am using create-react-app.
If I understand your requirement properly, you want the similar usage of console.log (without importing console), then below is something you can try.
In your index file, set it as a global object(for server side js) or window object (for client side js). So that , it can be accessed anywhere.
We had something like this with a mmiddleware(using redux-logger package):
const logger = require('redux-logger').createLogger
return middleware.concat(logger({
collapsed: true,
duration: true
}))
Hope this helps!
What you're trying to do sounds like a bad way to do it. I think the best solution if you need custom data logged, would be to create/add a middleware. Or in React's case maybe a wrapper component. I'm not sure.
Otherwise look into React / Redux Dev Tools Extension.
https://github.com/facebook/react-devtools
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
Edit:
If you want to ignore good practices then you can do this:
// in index.js or app.js or wherever
import { logger } from 'utils/logging'
// if you have an env for development use it here
process.NODE_ENV = 'development' && window.logger = logger
// or just
window.logger = logger
// SomeComponent.js
window.logger()
Let's say I have 5 jsx files and each file uses some config parameter.
My index.js file imports all of these 5 jsx files.
Instead of having my config data spread accross 5 files, is there a way for my jsx files to get the data from a global JS object which has loaded the data from a config file?
I've seen some examples, but I've not been able to get them to work.
JS6 import function | Example using webpack
Assuming ES6:
config.js
export const myConfig = { importantData: '', apiUrl: '', ... };
Then:
jsxFileOne.js, jsxFileTwo.js, ...
import { myConfig } from 'config.js';
There are other ways to import & export things globally leveraging webpack, but this should get you started.
If your project is built using Webpack, consider using node-env-file.
Example config file snippets:
development.env
API_SERVER_URL=https://www.your-server.com
webpack.config.js
const envFile = require('node-env-file');
...
const appSettingsFile = isDevBuild ? '/settings/development.env' : '/settings/production.env';
try {
envFile(path.join(__dirname + appSettingsFile));
} catch (error) {
console.log("Failed to read env file!: " + __dirname + appSettingsFile);
}
...
plugins: [
new webpack.DefinePlugin({
"process.env": {
API_SERVER_URL: JSON.stringify(process.env.API_SERVER_URL)
}
})
...
]
Inside your js/jsx code, you can now access process.env.API_SERVER_URL variable which will contain the required value.
It seems dotenv package is more popular, you can try this out as well.
Very old problem, that nobody took the time to solve, until now. I leave this for future readers because this is a top search result for configuration in React.
I created wj-config to deal exactly with this. Be sure to pay close attention to the React notes as you will need to enable top-level awaits in webpack, either by ejecting or using the #craco/craco NPM package.
You may also read this blog post that explains its use.