Webpack conditional require - javascript

I'm writing an isomorphic Key Value Store with webpack.
This is currently my approach to load the libraries, which obviously doesn't work, because webpack wants to resolve both require.
Whats' the right approach?
var db = null;
if (typeof window === 'undefined') {
// node context
db = require('level');
} else {
// browser context
db = require('gazel');
}
I know, that you can provide a target to webpack.
But I have no idea how to use that.
Thanks!

I think resolve.alias would work for you. You would set db module to point at level or gazel depending on which build you are creating.

webpack.config.js
module.exports = {
plugins: [
new webpack.DefinePlugin({
"process.env": {
BROWSER: JSON.stringify(true)
}
})
]}
your-universal.js
var db = null;
if (!process.env.BROWSER) {
// node context
db = require('level');
} else {
// browser context
db = require('gazel');
}

Related

Issue handling file download from cypress

While I was working on Cypress trying to download a .xlsx report and further manipulate the data in it for further verification, problem I faced was when Cypress was running test with the electron browser-it prompted a window based popup.
Moreover, when i selected chrome browser for running tests, the default directory of download directory could not be modified. Hence, manipulation of data wasn't possible if it's not present in the project directory as it would cause faliures in the CI execution...
Any workaround for this would be appreciated.
I solved it with the index.js file in the plugins folder by doing the following stuff:
const cypressTypeScriptPreprocessor = require('./cy-ts-preprocessor');
const path = require('path');
const fs = require('fs');
const RESULT_FOLDER = 'results';
const downloadDirectory = path.join(__dirname, '..', RESULT_FOLDER);
module.exports = on => {
on('file:preprocessor', cypressTypeScriptPreprocessor);
on('before:browser:launch', (browser = {}, options) => {
if (fs.existsSync(downloadDirectory)) {
fs.rmdirSync(downloadDirectory, { recursive: true });
}
if (browser.family === 'chromium' && browser.name !== 'electron') {
options.preferences.default['download'] = { default_directory: downloadDirectory };
return options;
}
if (browser.family === 'firefox') {
options.preferences['browser.download.dir'] = downloadDirectory;
options.preferences['browser.download.folderList'] = 2;
return options;
}
});
};
The documentation for that you will find here: https://docs.cypress.io/api/plugins/browser-launch-api.html#Change-download-directory
Be aware this works for Chromium browsers but currently not for the Electron browser in CI mode. Cypress knows about the issue and is currently implementing a solution for that: https://github.com/cypress-io/cypress/issues/949#issuecomment-755975882
You can change the download path in your test like below.
const downloadFolder = path.resolve(__dirname, '../users/user/source/repos/containingRoot/cypress/downloads');

Rename webpack/gatsby chunkmapping strings

When building our production app in Gatsby, I see something like this:
window.___chunkMapping={
"app":[],
"component---src-templates-page-tsx":[],
"component---src-templates-pages-newsletter-tsx":[]
}
Is it possible to hash these paths instead of printing them out? We don‘t want to expose too much from what is happening in the back.
I tried setting these configs in webpack:
output: {
filename: `[chunkhash:2][contenthash:5].js`,
chunkFilename: `[chunkhash:2][contenthash:5].js`,
},
And it successfully hashes .js files but not the template paths.
I upvoted this question when I first saw it, I think it's definitely should be done in production build.
Unfortunately, componentChunkName (the template path in question) is generated by Gatsby in createPage & not handled by webpack.
The code that generates componentChunkName is over here: github
I tried to modify the code as follow:
const { kebabCase } = require(`lodash`)
const path = require(`path`)
+ const uuidv5 = require(`uuid/v5`)
const { store } = require(`../redux`)
const generateComponentChunkName = componentPath => {
const program = store.getState().program
let directory = `/`
if (program && program.directory) {
directory = program.directory
}
const name = path.relative(directory, componentPath)
- return `component---${kebabCase(name)}`
+ return process.env.NODE_ENV === `production`
+ ? `component---${uuidv5(name, uuidv5.URL)}`
+ : `component---${kebabCase(name)}`
}
exports.generateComponentChunkName = generateComponentChunkName
This successfully hides all the component names in production build:
app: Array [ "/app-e593b3d93932ed3a0363.js" ]
"component---11d478fe-6a55-579c-becf-625ab1e57cf4": Array [ "/component---11d478fe-6a55-579c-becf-625ab1e57cf4-76c90ae50035c52657a0.js" ]
"component---15c76861-b723-5e0a-823c-b6832aeeb0a0": Array [ "/component---15c76861-b723-5e0a-823c-b6832aeeb0a0-18eb457ba6c147e1b31b.js" ]
...
None of the local unit tests failed, my clicking-around-until-something-breaks test also hasn't yielded any errors. I might submit a PR later today to see if the maintainers have some insights on why this is not a good idea.
Edit: I opened an issue instead: github, you can subscribe to the issue to see how it resolves.

Can't save/create files using Store.js

So I wanted to save a file on the client storage using Store.js.
I can change the date using store.set and i can log it to console to see the change, but then it's supposed to be saved in app data where it's not created.
I tried to get the Path where it's being saved and it's :
C:\Users\USER\AppData\Roaming\stoma2/Categories.json
I noticed that there is a "/" so I tried :
C:\Users\USER\AppData\Roaming\stoma2\Categories.json
and :
C:/Users/USER/AppData/Roaming/stoma2/Categories.json
But all 3 of them didn't work.
This is my Store.js :
const fs = require('browserify-fs');
var fs2 = require('filereader'),Fs2 = new fs2();
const electron = window.require('electron');
const path = require('path');
class Store {
constructor(opts) {
// Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
// app.getPath('userData') will return a string of the user's app data directory path.
//const userDataPath = (electron.app || electron.remote.app).getPath('userData');
var userDataPath = (electron.app || electron.remote.app).getPath('userData');
for(var i=0;i<userDataPath.length;i++){
if(userDataPath.charAt(i)=="\\"){
userDataPath = userDataPath.replace("\\","/");
}
}
// We'll use the `configName` property to set the file name and path.join to bring it all together as a string
this.path = path.join(userDataPath, opts.configName + '.json');
this.data = parseDataFile(this.path, opts.defaults);
console.log(this.path);
}
// This will just return the property on the `data` object
get(key) {
return this.data[key];
}
// ...and this will set it
set(key, val) {
this.data[key] = val;
// Wait, I thought using the node.js' synchronous APIs was bad form?
// We're not writing a server so there's not nearly the same IO demand on the process
// Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
// we might lose that data. Note that in a real app, we would try/catch this.
fs.writeFile(this.path, JSON.stringify(this.data));
}
}
function parseDataFile(filePath, data) {
// We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
// `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
try {
return JSON.parse(Fs2.readAsDataURL(new File(filePath)));
} catch(error) {
// if there was some kind of error, return the passed in defaults instead.
return data;
}
}
// expose the class
export default Store;
There might be a probleme fith js.writeFile() (well that's the source of probleme).
and this is my call :
//creation
const storeDefCat = new Store({
configName: "Categories",
defaults: require("../data/DefaultCategorie.json")
})
//call for the save
storeDefCat.set('Pizza',{id:0,path:storeDefCat.get('Pizza').path});
For now if possible,I might need to find another way to save the file.
And i tried : fs : It doesn't work for me for some reason (I get strange errors that they don't want to be fixed..) .
If anyone has an Idea then please I would be grateful.
So I managed to fix the probleme, Why fs was sending me errors about undefined functions?Why file wasn't getting created ? It has NOTHING to do with the code it self, but the imports...
To clearify, I was using :
const fs = require('fs');
And the solution is to make it like :
const fs = window.require('fs');
Just adding window. fixed all the problems .Since it's my first time using electron I wasn't used to import from the window but it seems it's necessary.And more over...There was no posts saying this is the fix.

Unable to read config.json file in node.js

I am writing a unit test case for the , question is mentioned in the link How to stub/mock submodules of a require of nodejs using sinon
when I include a require
const index=require('./index.js');
It has a library require inside it
const library= require('./library.js');
the library.js file has a require which reads config.json file(this config file is also required inside above index.js) as below
const readConfig = require('read-config');
const config = readConfig('./config.json');
I have tried many ways as suggested in the above link but I am failing
const stubs = {
'./library': function (response) {
assert.equal(some, null);
return 'Some ' + argument;
},
'../library1.js': {
function(paths, opts){
var config='./config.json'
return config;
}
},
}
const index=proxyquire('./index.js',stubs)
When I run my unit test case I am still getting the below error
throw configNotFound(configPath);
^
ReadConfigError: Config file not found: ./config.json
I would like to know which part of the code I am missing badly that the code throws the error
I am trying to edit the index.js and all the related files where config is read with the below code
var path = require('path');
var pathToJson = path.resolve(__dirname, '../config.json');
// Load config
var config = fs.readFile(pathToJson , 'utf8', function (err, data) {
if (err) throw err;
config = JSON.parse(data);
});
Here challenge is that I cannot change the node code
You problem is likely to be path resolution. If ./config.json is relative to where you are running Node from (process.cwd()), then it'll work. If it's relative to your library module, then you can do something like:
// Works for JS and JSON
const configPath = require.resolve('./config.json');
// Works in general
const configPath = require('path').join(__dirname, 'config.json');
// Then
const readConfig = require('read-config');
const config = readConfig(configPath);
It's difficult to say if this is the case without knowing more about your project layout and how you're starting your app.

Common logging for node, express application -- best practice?

I'm working on an node.js application with several dozen modules and using bunyan for logging (JSON output, multiple configurable streams). I've been looking for good examples of how to implement a instance across all the modules, but haven't seen what appears to be a really clean example I can learn from.
Below illustrates an approach that works, but seems quite inelegant (ugly) to me. I'm new to node & commonjs javascript in general, so looking for recommendations on how to improve it.
module: ./lib/logger
// load config file (would like this to be passed in to the constructor)
nconf.file({ file: fileConfig});
var logSetting = nconf.get('log');
// instantiate the logger
var Bunyan = require('bunyan');
var log = new Bunyan({
name: logSetting.name,
streams : [
{ stream : process.stdout,
level : logSetting.stdoutLevel},
{ path : logSetting.logfile,
level : logSetting.logfileLevel}
],
serializers : Bunyan.stdSerializers
});
function Logger() {
};
Logger.prototype.info = function info(e) { log.info(e) };
Logger.prototype.debug = function debug(e) { log.debug(e) };
Logger.prototype.trace = function trace(e) { log.trace(e) };
Logger.prototype.error = function error(e) { log.error(e) };
Logger.prototype.warn = function warn(e) { log.warn(e) };
module.exports = Logger;
module: main app
// create the logger
var logger = require('./lib/logger)
var log = new logger();
// note: would like to pass in options --> new logger(options)
module: any project module using logger
// open the logger (new, rely on singleton...)
var logger = require('./lib/logger');
var log = new logger();
or view the gist
any recommendations?
EDIT:
I've modified the constructor, making the singleton pattern explicit (rather than implicit as part of the 'require' behaviour.
var log = null;
function Logger(option) {
// make the singleton pattern explicit
if (!Logger.log) {
Logger.log = this;
}
return Logger.log;
};
and then changed the initialization to take an options parameter
// initialize the logger
Logger.prototype.init = function init(options) {
log = new Bunyan({
name: options.name,
streams : [
{ stream : process.stdout,
level : options.stdoutLevel},
{ path : options.logfile,
level : options.logfileLevel}
],
serializers : Bunyan.stdSerializers
});
};
Singleton pattern in nodejs - is it needed?
Actually, singleton is perhaps not needed in Node's environment. All you need to do is to create a logger in a separate file say, logger.js:
var bunyan = require("bunyan"); // Bunyan dependency
var logger = bunyan.createLogger({name: "myLogger"});
module.exports = logger;
Then, retrieve this logger from another module:
var logger = require("./logger");
logger.info("Anything you like");
if you are using express with node.js then you can try this.
By default, logging is disabled in Express. You have to do certain stuff to get logs working for your app. For access logs, we need to use the Logger middleware; for error logs we will use Forever.Hope it will help you..
Here is a good example How to Logging Access and Errors in node.js

Categories