electron-react-boilerplate
electron-react-boilerplate copied to clipboard
Custom Protocol for Deep Link no working in Development
Hello, I'm created custom protocol for deep link. code is like bottom.
src/main/main.ts
app.removeAsDefaultProtocolClient('customtest');
if (process.defaultApp) {
console.log(process.execPath);
console.log(process.argv);
if (process.env.NODE_ENV === 'development' && process.platform === 'win32') {
app.setAsDefaultProtocolClient('customtest', process.execPath, [
process.argv[1],
path.resolve(process.argv[2]),
process.argv[3],
path.join(
__dirname,
'..',
'..',
'node_modules',
'ts-node',
'register',
'transpile-only.js'
),
path.resolve(process.argv[5]),
]);
} else if (process.platform === 'win32') {
app.setAsDefaultProtocolClient('customtest', process.execPath, []);
} else {
app.setAsDefaultProtocolClient('customtest');
}
} else {
app.setAsDefaultProtocolClient('pixellauncher', process.execPath);
}
const gotTheLock = app.requestSingleInstanceLock();
(skip)
app.on('open-url', (event, url) => {
dialog.showErrorBox('Welcome Back', `You arrived from: ${url}`);
});
When I package the app, it's working well. but run development with
npm run start
, then it cause the error "unable to parse" like this.
[
'C:\\Users\\tilto\\Documents\\git-projects\\***\\node_modules\\electron\\dist\\electron.exe',
'--require',
'C:\\Users\\tilto\\Documents\\git-projects\\***\\node_modules\\electronmon\\src\\hook.js',
'-r',
'ts-node/register/transpile-only',
'.'
]
I checked process argument like this. so this is protocol set in development.
app.setAsDefaultProtocolClient('customtest', process.execPath, [
process.argv[1],
path.resolve(process.argv[2]),
process.argv[3],
path.join(
__dirname,
'..',
'..',
'node_modules',
'ts-node',
'register',
'transpile-only.js'
),
path.resolve(process.argv[5]),
]);
How can I get Custom Protocol for Deep Link to work in Development in Electron React Boilerplate?
same question, It's work in package.
I don't find more explanation about deep link.
What do these two sentences mean?
doc path string (optional) Windows - The path to the Electron executable. Defaults to process.execPath args string[] (optional) Windows - Arguments passed to the executable. Defaults to an empty array
Was having the same issue in development mode. For me the following approach worked:
app.setAsDefaultProtocolClient('customtest', process.execPath, [
'-r',
'ts-node/register/transpile-only',
'.',
]);
In my case process.execPath
was pointing to 'C:\\Users\\***\\node_modules\\electron\\dist\\electron.exe'
.
Depending on your setup you may need to resolve '.'
to an absolute path.
Hope this helps you as well 🤞
Was having the same issue in development mode. For me the following approach worked:
app.setAsDefaultProtocolClient('customtest', process.execPath, [ '-r', 'ts-node/register/transpile-only', '.', ]);
In my case
process.execPath
was pointing to'C:\\Users\\***\\node_modules\\electron\\dist\\electron.exe'
. Depending on your setup you may need to resolve'.'
to an absolute path.Hope this helps you as well 🤞
Hey, regarding your workaround, what am I looking to point it to? When I paste your code it says it cannot find the module "ts-node/register/transpile-only/ so I don't even hink it is at the point where its looking at the relative or absolute path yet. I've been trying to make this work for 3 weeks i'm really losing my mind on this.......
@Sabin-DC ,
if ( process.env.NODE_ENV === 'development' && process.platform === 'win32') { app.setAsDefaultProtocolClient(APP_PROTOCOL, process.execPath, [ '-r', path.resolve(__dirname,'..','..','node_modules','ts-node/register/transpile-only'), path.resolve(__dirname,'..','..'), ]); } else { app.setAsDefaultProtocolClient(APP_PROTOCOL); }
Depending on your folder path you need to adjust the depth or not. There seems to be a problem with global ts-node when given the argument so you must explicitely set both paths.
@Sabin-DC ,
if ( process.env.NODE_ENV === 'development' && process.platform === 'win32') { app.setAsDefaultProtocolClient(APP_PROTOCOL, process.execPath, [ '-r', path.resolve(__dirname,'..','..','node_modules','ts-node/register/transpile-only'), path.resolve(__dirname,'..','..'), ]); } else { app.setAsDefaultProtocolClient(APP_PROTOCOL); }
Depending on your folder path you need to adjust the depth or not. There seems to be a problem with global ts-node when given the argument so you must explicitely set both paths.
The error i'm getting right now is that it says it "Cannot find module 'ts-node/register/transpile-only'. Is this because I don't have ts-node installed globally? Or perhaps the path for my app?
@Sabin-DC , yes. It throws that error because "path.resolve(__dirname,'..','..','node_modules','ts-node/register/transpile-only')" is not pointing correctly. Can you try to debug this by looking at your folder paths ? The thing I did fixed it for me, thanks to @IanStorm . Also you can try debugging by getting the "process.execPath" and then running in the terminal the command until it works, by replacing the variables with the actual locations.
@Sabin-DC , yes. It throws that error because "path.resolve(__dirname,'..','..','node_modules','ts-node/register/transpile-only')" is not pointing correctly. Can you try to debug this by looking at your folder paths ? The thing I did fixed it for me, thanks to @IanStorm . Also you can try debugging by getting the "process.execPath" and then running in the terminal the command until it works, by replacing the variables with the actual locations.
When I console log process.execPath its giving me this:
"F:\Dev_Projects\React Projects\dummy2\node_modules\electron\dist\electron.exe".
This does exist and now that I copy & pasted your code and replaced APP_PROTOCOL with a custom protocol, if I call it it will open a second main window once with a white screen, so not focusing the existing one (I have to event handle that I suppose). However if I call the deeplink a second time within that same session then I get this error:
"Unable to find electron app at C:\WINDOWS\system32\testdeep:"
Not sure if by opening one window it's re-assigning the paths on this second pass and now it's just incorrectly assigned... I might just have to do an event handler properly for the first time I call to focus the main and not open a 2nd instance.
@Sabin-DC , yes. It throws that error because "path.resolve(__dirname,'..','..','node_modules','ts-node/register/transpile-only')" is not pointing correctly. Can you try to debug this by looking at your folder paths ? The thing I did fixed it for me, thanks to @IanStorm . Also you can try debugging by getting the "process.execPath" and then running in the terminal the command until it works, by replacing the variables with the actual locations.
Alright well some progress is made I think (at least in my understanding of it), now i'm pointing the app towards the /src/main/main.ts but it's still opening a new window with nothing inside so i'm not sure what exactly is going on. Is it not transpiling the typescript but still running it? This is so confusing without having any errors...
@Sabin-DC , well the second browserWindow exists there only for you to get the path, you need this in order to handle it properly https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app . You need to implement that "gotTheLock" in your app.
I solved this problem, but I used an alias to make it impossible to compile。 The plugin I use is: typescript-transform-paths
If you use the tsconfig-paths
plugin ,write a script
const path = require('path');
const old = process.cwd;
const basePath = path.resolve('D:\soft-dev\code\web\frame\React\electron-printer')
process.cwd = () => {
return basePath;
};
ts_node.register({
transpileOnly: true,
pretty:true,
files: true,
cwd: basePath,
dir: basePath,
projectSearchDir:basePath,
project:path.join(basePath,'tsconfig.json'),
require:[path.join(basePath,'node_modules','tsconfig-paths/register')],
});
process.cwd = old;
exec
app.setAsDefaultProtocolClient('customtest', process.execPath, [ '-r', 'script', process.cwd() ]);
This idea messed with me all day and all night!!!!!!!!!!!!!
Has anyone figured out a solution to this?
@amilajack do you perhaps have a solution for how this should be handled?
I don't unfortunately, I might find the time to repro this and put together a solution
I've been battling with this so far as well, but no luck.
Just for a note, this is relevant when you're using electronmon
+ typescript
!
This issue is relevant only to Windows!
@ifree92 @amilajack I managed to resolve it eventually by doing it like this:
// remove so we can register each time as we run the app.
app.removeAsDefaultProtocolClient(PROTOCOL_ID);
// If we are running a non-packaged version of the app && on windows
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient(PROTOCOL_ID, process.execPath, [
'-r',
path.join(
__dirname,
'..',
'..',
'node_modules',
'ts-node/register/transpile-only'
),
path.join(__dirname, '..', '..'),
]);
} else {
app.setAsDefaultProtocolClient(PROTOCOL_ID);
}
Also very IMPORTANT: Don't run the process as an Administrator on Windows, the deep links never work that way in development.
@harismuha123 thank you for the example. Looks like it still doesn't work. It looks like it is trying to open the second instance of the app.
But I will play around, will see what I can do.
@harismuha123 thank you for the example. Looks like it still doesn't work. It looks like it is trying to open the second instance of the app.
But I will play around, will see what I can do.
You need to implement the single instance locking mechanism from the Electron documentation on deep links in Windows. Otherwise it will always try opening a second instance.
@harismuha123 Using your example I faced another problem in that my tsconfig.json
file has not been read as expected.
I did not find a way to specify over -r ts-node/register
the specific tsconfig.json
file.
No, actually, there was a way to do that using TS_NODE_PROJECT
env variable, but no way to specify this variable while registering the protocol.
So I found another workaround.
Just create the file, e.g.: your-electron-project/dev-main.js
with the following code:
const path = require('path');
require('ts-node').register({
project: path.resolve(__dirname, 'tsconfig.custom.json'),
transpileOnly: true,
});
require('./src/main/main.ts');
So the your-electron-project/src/main/main.ts
file would look like:
// remove so we can register each time as we run the app.
app.removeAsDefaultProtocolClient(PROTOCOL_ID);
// If we are running a non-packaged version of the app && on windows
if (process.argv.length >= 2) {
app.setAsDefaultProtocolClient(PROTOCOL_ID, process.execPath, [path.join(__dirname, '..', '..', 'dev-main.js')]);
} else {
app.setAsDefaultProtocolClient(PROTOCOL_ID);
}
Run your project using the following script:
{
"scripts": {
"start": "electronmon dev-main.js"
}
}
Now it works for me.
@ifree92 @amilajack I managed to resolve it eventually by doing it like this:
// remove so we can register each time as we run the app. app.removeAsDefaultProtocolClient(PROTOCOL_ID); // If we are running a non-packaged version of the app && on windows if (process.argv.length >= 2) { app.setAsDefaultProtocolClient(PROTOCOL_ID, process.execPath, [ '-r', path.join( __dirname, '..', '..', 'node_modules', 'ts-node/register/transpile-only' ), path.join(__dirname, '..', '..'), ]); } else { app.setAsDefaultProtocolClient(PROTOCOL_ID); }
Also very IMPORTANT: Don't run the process as an Administrator on Windows, the deep links never work that way in development.
This solution worked for me as well. I don't have to change anything elsewhere.
Thanks for the help.
What's important for calling app.setAsDefaultProtocolClient
on Windows is that the first item in the args
parameter array is the path to the directory where the package.json
for your Electron app is located.
Consider the following example. Let's say you have a CLI argument --app-data-path
that you can pass to your Electron app like this:
$ npx electron --user-data-path={./foo} .
In this scenario, calling app.setAsDefaultProtocolClient('customtest', process.execPath, [process.argv[1], ... ])
won't work as process.argv[1]
is --user-data-path={./foo}
, and then you'll be getting the error "Error launching app".
One option to fix this would be to find the path in process.argv
, put in front when passing to app.setAsDefaultProtocolClient
, and then pass the rest of process.argv
.