Configuring a forked process entry point with Electron-Builder - javascript

I am using electron-builder#23.6 and am forking a process to run in the background, which works correctly running npm run dev and npm run start.
e.g.
const childPath = app.isPackaged
? path.join(process.resourcesPath, './src/main/child.js')
: path.join(__dirname, '../../src/main/child.js')
const child = fork(childPath, ['initialize'], {
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
})
The child.js file also has two node_module dependencies that I have included in the asarUnpack section of my electron-builder.yml file
asarUnpack:
- '**/*.{node.dll}'
- '**/node_modules/dependency_1'
- '**/node_modules/dependency_2'
The issues I am having are:
I am able to access the child.js file if I move it to a root level folder and add that to extraResources - but in that case it does not seem to be able to access its node_module dependencies.
If I move it into the main application folder, as shown above, then I don't seem to be able to get electron-builder to copy the child.js file into out/main. I have tried including from/to definitions in files and extraResources
Can someone point me in the right direction or to a functional example somewhere?
I am expecting to be able to package the application with the child.js application available to be called (like in the code above) in a manner in which it will have access to its node_module dependencies, despite being outside of the build lifecycle dependencies of main, preload and renderer targets.
I have tried the examples defined and approaches defined above.

Related

Problem writing to file fs module, apparently the path is positioned at the root level

I'm practicing with typescript and I want to write a file using fs module but I don't know if is this a noob question or I'm doing something wrong but my project look like this:
root
-> dir (here are the js result from tsc)
-> src
--> data
---> data.json
--> service
---> service.ts
--> index.ts
-> package.json
-> tsconfig.json
And at service.ts apparently the path is:
let filePath = path.join('./','src','data','data.json') // this works
fs.writeFile(filePath, JSON.stringify(data,null,2), 'utf8', (err)=>{ if(err){ return console.log(err);}})
So I don't know why the path is positioned at the root level
If I try "../data/data.json" I get ENOENT ERROR no such file or directory
Is it ok?
Filesystem operations with relative paths always use the Current Working Directory - a concept explained here: https://en.m.wikipedia.org/wiki/Working_directory
When you run Node.js, you do so while being in a particular directory. For example, scripts such as npm start are usually executed in the root-level directory of a repository/project - this causes all relative paths to resolve starting from there. Note, however, that this may be different in production - it is possible for Docker, PM2, systemd, or any other tool to run your script while being in a different working directory (this can often be configured).
To inspect your current working directory in Node.js, use https://nodejs.org/api/process.html#processcwd
It is also possible to build paths relative to the directory of the JS file. This tutorial shows various examples on how to do that: https://www.digitalocean.com/community/tutorials/nodejs-how-to-use__dirname
It is important to remember that require() uses paths relative to __dirname, but fs resolves relative to CWD.

Ember.js: How to share package JSON file dependency to child engines and addons

Basically I need to know how Ember Js can share parent app package.json file dependency(xyz:3.0.0) to child engine and addons without being used again in child engine and addon package.json file. So that I can reduce the size of the application.
As of now in our application we installing common package dependency in all our child engines and addons even though we used in parent app its increases application size.
Here is my clear example of my project scenario.
parentApp(xxx):
Which has package.json file containes few dependency like ex: vendor-package1:10.0.0, vendor-package2:4.0.0, Child Engine1(yyy), Child Engine2(zzz)
Child Engine1(yyy)
Which has package.json file containes few dependency like ex: vendor-package1:10.0.0, vendor-package2:4.0.0
Child Engine2(zzz)
Which has package.json file containes few dependency like ex: vendor-package1:10.0.0, vendor-package2:4.0.0
So if you notice parent app and child engines has same dependency(vendor-package1:10.0.0, vendor-package2:4.0.0) which I need to do npm install for all three app. I'm adding (vendor-package:10.0.0, vendor-package2:4.0.0) to all my child engines because it should available to my engines.
Because of this my dist folder has (vendor-package1:10.0.0, vendor-package2:4.0.0) to all my parentApp and engines, which increase in size.
If I add(vendor-package1:10.0.0, vendor-package2:4.0.0) only to my parentApp(xxx) then my child engines cannot access those component inside vendor-package1 and vendor-package2.
Please suggest some solution where I don't want to add dependency to all my apps.
I've setup a demo ember 3.12 app at https://github.com/bartocc/so-58343095.
This app depends on ember-concurrency and also has an in-repo addon core that depends on ember-concurrency.
I've also added ember-cli-bundlesize to help analyse the bundle size of the built app.
Here are the results of ember bundlesize:test before and after adding the in-repo addon.
Before
$ git checkout 6c5dfc7
$ ember bundlesize:test
ok 1 - app:javascript: 165.89KB <= 500KB (gzip)
ok 2 - app:css: 40B <= 50KB (gzip)
After
$ git checkout 9c9c9a9
$ ember bundlesize:test
ok 1 - app:javascript: 165.89KB <= 500KB (gzip)
ok 2 - app:css: 40B <= 50KB (gzip)
Bundlesize check was successful. Good job!
As you can see, the bundlesize does not change.
The same goes for an in-repo engine:
With in-repo engine depending on ember-concurrency
$ git checkout 2662b63
$ ember bundlesize:test
ok 1 - app:javascript: 170.08KB <= 500KB (gzip)
ok 2 - app:css: 40B <= 50KB (gzip)
Bundlesize check was successful. Good job!
The small difference you see between 165.89KB and 170.08KB is made of:
the ember-engines modules:
;define("ember-engines/-private/engine-ext")
;define("ember-engines/-private/engine-instance-ext")
;define("ember-engines/-private/route-ext")
;define("ember-engines/-private/router-ext")
;define("ember-engines/components/link-to-component")
;define("ember-engines/components/link-to-external-component")
;define("ember-engines/engine")
;define("ember-engines/initializers/engines")
;define("ember-engines/routes")
the my-engine modules:
;define("my-engine/config/environment")
;define("my-engine/engine")
;define("my-engine/resolver")
;define("my-engine/routes")
;define("my-engine/templates/application")
And finally the ember-concurrency modules aliased to be available inside the my-engine resolver:
;define.alias("ember-concurrency/helpers/cancel-all", "my-engine/helpers/cancel-all");
;define.alias("ember-concurrency/helpers/perform", "my-engine/helpers/perform");
;define.alias("ember-concurrency/helpers/task", "my-engine/helpers/task");
;define.alias("ember-concurrency/initializers/ember-concurrency", "my-engine/initializers/ember-concurrency");
YMMV depending on what addon you use though, but you can use this demo app as a starting point to check whether some code is really duplicated or not.
Hope this helps
Update in answer to updated question 11/12/19
The short answer is you cannot make each of your dependencies only part of your app's package.json. What you have where you specify each dependency in each addon and app's package.json is correct.
Npm will only install one version of each package. It does some complicated 'magic' to resolve which dependency gets used. If you think about it, this is the only thing that could happen because JS and the browser can only have on version of each library available since things are made available globally on the window. Your app would have now way of telling the difference between version x.x.x of a library and x.x.y of the same library because that library is always exposed with the same name globally, e.g., Ember.
Original answer
We have had some success reducing packages installed by using lerna and a mono repo: https://github.com/lerna/lerna. Note however, we have not had any success using the lerna commands. Instead we simply run npm i in each addon/app. The order npm i is run is critical: you must start with the base of your tree first i.e., start with the addon that does not consume an of your other addons/apps and move your way up.
Our mono repo contains three ember applications and two addons:
addon-1
addon-2
- consumes addon-1
app-1
- consumes addon-1
app-2
- consumes addon-1 and addon-2
app-3
- consumes addon-1 and addon-2
In the structure above, npm i must be run in this order: addon-1, addon-2 and app-1, app-2 and app-3.
We have experimented with different ways of including the packages in package.json of each addon/app. It's come down to this, example for app-2:
"devDependencies": {
"addon-1": "file:../addon-1",
"addon-2": "file:../addon-2",
},
file: allows you to reference a module in your mono repo using a relative path.

Is there a way to cause the JS engine to load a .js file without explicitly importing something from it?

Maybe I'm trying to do something silly, but I've got a web application (Angular2+), and I'm trying to build it in an extensible/modular way. In particular, I've got various, well, modules for lack of a better term, that I'd like to be able to include or not, depending on what kind of deployment is desired. These modules include various functionality that is implemented via extending base classes.
To simplify things, imagine there is a GenericModuleDefinition class, and there are two modules - ModuleOne.js and ModuleTwo.js. The first defines a ModuleOneDefinitionClass and instantiate an exported instance ModuleOneDefinition, and then registers it with the ModuleRegistry. The second module does an analogous thing.
(To be clear - it registers the ModuleXXXDefinition object with the ModuleRegistry when the ModuleXXX.js file is run (e.g. because of some other .js file imports one of its exports). If it is not run, then clearly nothing gets registered - and this is the problem I'm having, as I describe below.)
The ModuleRegistry has some methods that will iterate over all the Modules and call their individual methods. In this example, there might be a method called ModuleRegistry.initAllModules(), which then calls the initModule() method on each of the registered Modules.
At startup, my application (say, in index.js) calls ModuleRegistry.initAllModules(). Obviously, because index.js imports the exported ModuleRegistry symbol, this will cause the ModuleRegistry.js code to get pulled in, but since none of the exports from either of the two Module .js files is explicitly referenced, these files will not have been pulled in, and so the ModuleOneDefinition and ModuleTwoDefinition objects will not have been instantiated and registered with the ModuleRegistry - so the call to initAllModules() will be for naught.
Obviously, I could just put meaningless references to each of these ModuleDefinition objects in my index.js, which would force them to be pulled in, so that they were registered by the time I call initAllModules(). But this requires changes to the index.js file depending on whether I want to deploy it with ModuleTwo or without. I was hoping to have the mere existence of the ModuleTwo.js be enough to cause the file to get pulled in and the resulting ModuleTwoDefinition to get registered with the ModuleRegistry.
Is there a standard way to handle this kind of situation? Am I stuck having to edit some global file (either index.js or some other file it references) so that it has information about all the included Modules so that it can then go and load them? Or is there a clever way to cause JavaScript to execute all the .js files in a directory so that merely copying the files it would be enough to get them to load at startup?
a clever way to cause xxJavaScriptxx Node.js to execute all the .js files in a directory:
var fs = require('fs') // node filesystem
var path = require('path') // node path
function hasJsExtension(item) {
return item != 'index.js' && path.extname(item) === '.js'
}
function pathHere(item) {
return path.join('.', item)
}
fs.readdir('./', function(err, list) {
if (err) return err
list.filter(hasJsExtension).map(pathHere).forEach(require) // require them all
})
Angular is pretty different, all the more if it is ng serve who checks if your app needs a module, and if so serves the corresponding js file, at any time needed, not at first load time.
In fact your situation reminds me of C++ with header files Declaration and cpp files with implementation, maybe you just need a defineAllModules function before initAllModules.
Another way could be considering finding out how to exclude those modules from ng-serve, and include them as scripts in your HTML before the others, they would so be defined (if present and so, served), and called by angular if necesary, the only cavehat is the error in the console if one script tag is not fetched, but your app will work anyway, if it supposed to do so.
But anyway, it would be declaring/defining those modules somewhere in ng-serve and also in the HTML.
In your own special case, and not willing to under-evalute ng-serve, but is the total js for your app too heavy to be served at once? (minified and all the ...), since the good-to-go solution may be one of the many tools to build and rebuild your production all.js from your dev js folder at will, or like you said, with a drag&drop in your folder.
Such tool is, again, server-side, but even if you only can push/FTP your javascript, you could use it in your prefered dev environment and just push your new version. To see a list of such tools google 'YourDevEnvironment bundle javascript'.
To do more with angular serve and append static js files under specific conditions, you should use webpack so the first option i see here is eject your webpack configuration and after that you can specify what angular should load or not.
With that said, i will give an example:
With angular cli and ng serve any external javascript files you wanna include, you have to put them inside the scripts array in the angular-cli.json file.However you can not control which file should be included and which one not.
By using webpack configuration you can specify all these thing by passing a flag from your terminal to the webpack config file and do all the process right there.
Example:
var env.commandLineParamater, plugins;
if(env.commandLineParamater == 'production'){
plugins = [
new ScriptsWebpackPlugin({
"name": "scripts",
"sourceMap": true,
"filename": "scripts.bundle.js",
"scripts": [
"D:\\Tutorial\\Angular\\demo-project\\node_moduels\\bootstrap\\dist\\bootstrap.min.js",
"D:\\Tutorial\\Angular\\demo-project\\node_moduels\\jquery\\dist\\jquery.min.js"
],
"basePath": "D:\\Tutorial\\Angular\\demo-project"
}),
]}else{
plugins = [
new ScriptsWebpackPlugin({
"name": "scripts",
"sourceMap": true,
"filename": "scripts.bundle.js",
"scripts": [
"D:\\Tutorial\\Angular\\demo-project\\node_moduels\\bootstrap\\dist\\bootstrap.min.js"
],
"basePath": "D:\\Tutorial\\Angular\\demo-project"
}),
]
}
then:
module.exports = (env) => {
"plugins": plugins,
// other webpack configuration
}
The script.js bundle will be loaded before your main app bundle and so you can control what you load when you run npm run start instead of ng-serve.
To Eject your webpack configuration, use ng eject.
Generally speaking, when you need to control some of angular ng-serve working, you should extract your own webpack config and customize it as you want.

Is it possible to call npm CLI app's main JS file as if it was ran within a subfolder?

I have a small npm CLI library which fixes errors in changelog.md's sitting at the same directory where CLI is called. I'm trying to write at least one unit test for it's CLI part (its API is a separate library and it's well-tested).
It's easy to trigger CLI's main JS file using execa library, like:
execa.sync('./cli.js')
but how do you trigger cli.js sitting in a root and meant to be looking for a ./changelog.md in a root, to execute on a different test file in a subfolder (/test/changelog.md)?
Mind you, there's real changelog.md file in the root which has nothing to do with unit test.
(Worst case scenario, we could copy cli.js into /test/, call it there via execa and delete later, but this looks not DRY solution)
My current AVA unit test is below. seed is incorrect changelog.md file. intended is correct changelog.md against which we'll compare later. I write seed contents into /test/changelog.md and want to run a CLI on it. Problem: how do I run ./cli.js against /test/package.json? Mind you, I still want my CLI API to be simple, not accept any arguments with paths (what could be a last resort solution — to accept custom path arguments).
My current test is nearly there, but it runs against root, ./package.json contents, not /test/package.json (which is how API would behave for end-user):
import path from 'path'
import fs from 'fs'
import test from 'ava'
import execa from 'execa'
test('01.01 - reads and writes correctly', t => {
var seed = fs.readFileSync(path.join('test', 'seed.md'), 'utf8')
var intended = fs.readFileSync(path.join('test', 'intended.md'), 'utf8')
fs.writeFileSync(path.join('test', 'changelog.md'), seed, 'utf8')
execa.sync('./cli.js') // <<< PROBLEM, this runs on root, not on ./test/changelog.md!
t.deepEqual(
fs.readFileSync(path.join('test', 'changelog.md'), 'utf8'),
intended,
'01.01'
)
})
How do you execute an npm CLI package on a different directory when unit testing, if it's meant to be ran on file present at the same level as CLI's JS file?
Thank you.

How to rename react-native entry file (index.ios.js)

When I init a react-native project, index.ios.js is created as project entry file.
Can I change this file's name and if so, how?
When you start a react-native app you'll see this message output by the React Packager:
Running packager on port 8081
and then:
Looking for JS files in
/Users/gbirman/gil/mapily
React packager ready.
By this point, the packager has compiled your JS files and is serving them with the .js extension renamed to .bundle. For example, your index.io.js file is compiled and served from:
http://localhost:8081/index.ios.bundle
If you added another file foo.js in the same directory as index.ios.js, the packager would serve it from:
http://localhost:8081/foo.bundle
You can confirm this by opening that url in your browser.
Now to answer your question, your project has an iOS/AppDelegate.m file with the following line:
jsCodeLocation = [NSURL URLWithString:#"http://localhost:8081/index.ios.bundle"];
... as you can see, it loads the index.ios.bundle. You can change the path/filename there to whatever you want, but it's probably best to stick with the recommended approach of naming your entry file index.io.js
Suppose you've moved your index.ios.js into a folder called dist. You need to do two things
For your development environment: Update jsBundleURLForBundleRoot in AppDelegate.m to match your updated path.
For your release bundle: Open your Xcode project. You'll need to update the Bundle React Native code and images task under Build Phases for your project. Update the shell script in this section to look like below:
export NODE_BINARY=node
../node_modules/react-native/packager/react-native-xcode.sh dist/index.ios.js
react-native-xcode.sh accepts the ENTRY_FILE as an optional first argument, defaulting to index.ios.js if none is found.
Updated Build Phases Example
Reference - react-native/scripts/react-native-xcode.sh

Categories