How to re-use platform parameter when building an electron application using `electron-forge make --platform=win32`? - circleci

We are building an electron desktop application for macos, linux, and windows.
Here is our electron-forge config:
// forge.config.js
const os = require('os')
const package = require('./package.json')
function getExtraResource() {
const p = os.platform()
switch (p) {
case 'darwin':
return ['./static/bin/pasteld-mac']
case 'linux':
return ['./static/bin/pasteld-linux']
case 'win32':
return ['./static/bin/pasteld-win.exe']
default:
throw new Error(
'forge.config.js error: your OS is not supported. Supported OS are: darwin, linux, win32',
)
}
}
function getIcon() {
const p = os.platform()
switch (p) {
case 'darwin':
return './static/icons/icon.icns'
case 'linux':
return './static/icons/icon.png'
case 'win32':
return './static/icons/icon.ico'
default:
throw new Error(
'forge.config.js error: your OS is not supported. Supported OS are: darwin, linux, win32',
)
}
}
module.exports = {
packagerConfig: {
name: package.productName,
executableName: package.name,
icon: getIcon(),
asar: true,
extraResource: getExtraResource(),
protocols: [
{
protocol: package.name,
name: package.name,
schemes: [package.protocolSchemes.native],
},
],
},
makers: [
{
name: '#electron-forge/maker-squirrel',
config: {
exe: `${package.name}.exe`,
setupIcon: './static/icons/icon.ico',
loadingGif: './static/icons/icon.gif',
iconUrl:
'https://raw.githubusercontent.com/pastelnetwork/pastel-electron-wallet/master/static/icons/icon.ico',
title: package.productName,
setupExe: `${package.productName} Setup - v${package.version}.exe`,
skipUpdateIcon: true,
},
},
{
name: '#electron-forge/maker-dmg',
config: {
icon: './static/icons/icon.icns',
name: package.productName,
},
},
{
name: '#electron-forge/maker-deb',
config: {
options: {
icon: './static/icons/icon.png',
},
},
},
],
plugins: [
[
'#electron-forge/plugin-webpack',
{
mainConfig: './webpack.main.config.js',
renderer: {
config: './webpack.renderer.config.js',
entryPoints: [
{
html: './src/index.html',
js: './src/renderer.tsx',
name: 'main_window',
},
],
},
},
],
],
}
As you can see in the above file, getExtraResource() detects the os type and pick the right executable file based on it. In other words, running run make on a proper platform is all we need to build the application.
However, we are now going to build the windows installer on linux wine image, more specifically using electronuserland/builder:wine-mono image.
Everything is working as expected so far, except one thing - we still need to add a step to the switch clause in the getExtraResource() to pick the windows executable in the builder image instead of linux executable(note that the builder image is still a linux image!).
It will be something like this:
# forge.config.js
//...
function getExtraResource() {
const p = os.platform()
switch (p) {
case 'darwin':
return ['./static/bin/pasteld-mac']
case 'linux':
if (build_arg === 'win32') {
return ['./static/bin/pasteld-win.exe']
}
return ['./static/bin/pasteld-linux']
case 'win32':
return ['./static/bin/pasteld-win.exe']
default:
throw new Error(
'forge.config.js error: your OS is not supported. Supported OS are: darwin, linux, win32',
)
}
}
//...
How can I get the build_arg in the above file?
Build command is yarn make --platform=win32 in the wine builder image.
Thanks in advance!

Electron Forge supports hooks and some of them get passed the platform and arch which you could save globally.
Currently the earliest hook that gets passed these is packageAfterCopy which might be called too late for your usage but worth a try:
plugins: [
// ...
],
hooks: {
packageAfterCopy: async (
forgeConfig,
buildPath,
electronVersion,
platform,
arch
) => {
console.log(buildPath, electronVersion, platform, arch);
},
}
}
I've also opened a PR to add these parameters to the generateAssets hook.

We could resolve this by using process.argv.
More specifically, we run this command to build windows installer in linux container:
yarn make --platform=win32
And the string win32 could be caught by process.argv[3] anywhere.
See the detailed implementation here.
Please advice if you have a better solution!

Related

remoteEntry.js not found on Jenkins

We are deploying a remote app written in NextJS and Typescript; The host app is in React only.
Currently the host app gets a 404 not found error as the remote app runs into this error in the Build Snapshot on Jenkins
+ ls ./dist/static/chunks/remoteEntry.js
ls: cannot access './dist/static/chunks/remoteEntry.js': No such file or directory
script returned exit code 2
However, the file is generated locally and both apps are able to spin up in local environment.
Here is our next.config.js:
const NextFederationPlugin = require('#module-federation/nextjs-mf');
const { exposedModules } = require('./lib/routes');
const version = process.env.VERSION_OVERRIDE || require('./package.json').version;
const deps = require('./package.json').dependencies;
// Note: This path needs to match with what's specified in CIRRUS_FRONTEND_ENTRYPOINT for www.
const assetBasePath = process.env.CDN_PATH ? `${process.env.CDN_PATH}${version}` : process.env.ASSET_BASE_PATH;
// Note: Heavily references module federation example meant for omnidirectional federation between Next apps.
// Changes mostly around path resolution due to our current resolution pattern via cdn
// https://github.com/module-federation/module-federation-examples/blob/master/nextjs/home/next.config.js
module.exports = {
webpack(config, options) {
Object.assign(config.experiments, { topLevelAwait: true });
// Integrated mode calls `next build` which has minimization by default. For local development, this is unnecessary.
if (process.env.NEXT_PUBLIC_ENVIRONMENT === 'INTEGRATED') {
config.optimization.minimize = false;
}
if (!options.isServer) {
console.log("Not Server");
config.output.publicPath = 'auto';
config.plugins.push(
new NextFederationPlugin({
name: 'cirrus',
filename: 'static/chunks/remoteEntry.js',
exposes: {
'./FederatedRouter': './lib/FederatedRouter',
...exposedModules
},
remoteType: 'var',
remotes: {},
shared: {
'#transcriptic/amino': {
requiredVersion: deps['#transcriptic/amino'],
singleton: true
},
react: {
requiredVersion: deps.react,
singleton: true
},
'react-dom': {
requiredVersion: deps['react-dom'],
singleton: true
},
'#strateos/micro-apps-utils': {
requiredVersion: deps['#strateos/micro-apps-utils'],
singleton: true
}
},
extraOptions: {
// We need to override the default module sharing behavior of this plugin as that assumes a nextjs host
// and thus next modules will be provided by the parent application.
// However, web is currently NOT a nextjs application so this child application so that assumption is
// invalid. Note that this means we need to ensure we explicitly specify common modules such as `react`
// in the `shared` key above.
skipSharingNextInternals: true
}
})
);
} else {
console.log("Is Server");
}
return config;
},
// Note: Annoyingly, NextJS automatically automatically appends a `_next` directory for assetPrefix
// but NOT public path so we'll have to manually include it here.
publicPath: `${assetBasePath}/_next/`,
// Note: If serving assets via CDN, assetPrefix is required to help resolve static assets.
// Also, NextJS automatically appends and expects a `_next` directory to the assetPrefix path.
// See https://nextjs.org/docs/api-reference/next.config.js/cdn-support-with-asset-prefix
assetPrefix: process.env.CDN_PATH ? assetBasePath : undefined,
distDir: 'dist',
// Use index react-router as fallback for resolving any pages that are not directly specified
async rewrites() {
return {
fallback: [
{
source: '/:path*',
destination: '/'
}
]
};
}
};
Tried upgrade NextJS from 12.1.6 to 12.2.2
Tried upgrade Webpack from 5.74.0 to 5.75.0
Cleaned cache by sh 'yarn cache clean'
Tried clear env by sh 'env -i PATH=$PATH make build-snapshot'
Hash of node modules by tar -cf - node_modules | md5sum
Downgraded "#module-federation/nextjs-mf" from 5.12.9 to 5.10.5
Verified file writing permission

Browsersync is running but does not refresh the page

I have MacOS + installed Docker container by Mark Shust (https://github.com/markshust/docker-magento) + installed browsersync on the host.
Magento has ".less" files in the folder: app/design/frontend. I set a folder as a current one in the cli. And run this command from the host:
browser-sync start --host "domain.test" --proxy "https://domain.test" --files "**/*.less" --https
I get this output:
[Browsersync] Proxying: https://domain.test
[Browsersync] Access URLs:
--------------------------------------
Local: https://localhost:3000
External: https://domain.test:3000
--------------------------------------
UI: http://localhost:3002
UI External: http://localhost:3002
--------------------------------------
[Browsersync] Watching files...
I can open https://domain.test and it works properly. http://localhost:3002 shows that there are no current connections. However, the output in the cli infoms: "[Browsersync] Reloading Browsers..."
if i change less, i still can find changes on the website but only after a manual reload.
The documentation mentions grunt configuration and there are some recipes as an example. I tried to use standard magento's file but it does not help. It looks like this:
module.exports = function (grunt) {
'use strict';
grunt.initConfig({
watch: {
files: 'app/design/**/*.less',
tasks: ['less']
},
browserSync: {
dev: {
bsFiles: {
src : [
'app/design/**/*.css'
]
},
options: {
watchTask: true,
server: './'
}
}
}
});
// load npm tasks
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-browser-sync');
// define default task
grunt.registerTask('default', ['browserSync', 'watch']);
var _ = require('underscore'),
path = require('path'),
filesRouter = require('./dev/tools/grunt/tools/files-router'),
configDir = './dev/tools/grunt/configs',
tasks = grunt.file.expand('./dev/tools/grunt/tasks/*'),
themes;
filesRouter.set('themes', 'dev/tools/grunt/configs/themes');
themes = filesRouter.get('themes');
tasks = _.map(tasks, function (task) {
return task.replace('.js', '');
});
tasks.push('time-grunt');
tasks.forEach(function (task) {
require(task)(grunt);
});
require('load-grunt-config')(grunt, {
configPath: path.join(__dirname, configDir),
init: true,
jitGrunt: {
staticMappings: {
usebanner: 'grunt-banner'
}
}
});
_.each({
/**
* Assembling tasks.
* ToDo: define default tasks.
*/
default: function () {
grunt.log.subhead('I\'m default task and at the moment I\'m empty, sorry :/');
},
/**
* Production preparation task.
*/
prod: function (component) {
var tasks = [
'less',
'cssmin',
'usebanner'
].map(function (task) {
return task + ':' + component;
});
if (typeof component === 'undefined') {
grunt.log.subhead('Tip: Please make sure that u specify prod subtask. By default prod task do nothing');
} else {
grunt.task.run(tasks);
}
},
/**
* Refresh themes.
*/
refresh: function () {
var tasks = [
'clean',
'exec:all'
];
_.each(themes, function (theme, name) {
tasks.push('less:' + name);
});
grunt.task.run(tasks);
},
/**
* Documentation
*/
documentation: [
'replace:documentation',
'less:documentation',
'styledocco:documentation',
'usebanner:documentationCss',
'usebanner:documentationLess',
'usebanner:documentationHtml',
'clean:var',
'clean:pub'
],
'legacy-build': [
'mage-minify:legacy'
],
spec: function (theme) {
var runner = require('./dev/tests/js/jasmine/spec_runner');
runner.init(grunt, { theme: theme });
grunt.task.run(runner.getTasks());
}
}, function (task, name) {
grunt.registerTask(name, task);
});};
Should it work without gruntjs running? And why the page reload is not triggered?
PS: I did not place this question into https://magento.stackexchange.com/ cause i believe it's a general problem and not related to Magento.

Electron application Can not find Squirrel

I build an electron app with auto-update enabled. After running the application on Windows, I got an error emitted by my application which is "Error: Can not find Squirrel".
After look into the code of electron project for finding the error message.
checkForUpdates () {
const url = this.updateURL;
if (!url) {
return this.emitError(new Error('Update URL is not set'));
}
if (!squirrelUpdate.supported()) {
return this.emitError(new Error('Can not find Squirrel'));
}
this.emit('checking-for-update');
squirrelUpdate.checkForUpdate(url, (error, update) => {
if (error != null) {
return this.emitError(error);
}
if (update == null) {
return this.emit('update-not-available');
}
this.updateAvailable = true;
this.emit('update-available');
squirrelUpdate.update(url, (error) => {
if (error != null) {
return this.emitError(error);
}
const { releaseNotes, version } = update;
// Date is not available on Windows, so fake it.
const date = new Date();
this.emit('update-downloaded', {}, releaseNotes, version, date, this.updateURL, () => {
this.quitAndInstall();
});
});
});
}
And after check the function squirrelUpdate.supported(). I know it is because the install location has no file "Update.exe".
I use electron-builder to generate my application and there is no Update.exe in unpacked packaged directory. How do I generate the Update.exe file?
The block of configuration of electron-builder in package.json is blow:
"win": {
"target": [
"nsis"
],
"defaultArch": "x64",
"verifyUpdateCodeSignature": false
},
How to solve the problem? Thanks.
The reason there is no update.exe is because you have "nsis" as the target package type.
The auto updater package you are trying to use is meant to be compatible with Squirrel.Windows. If you change your target to "squirrel" it will have the update.exe you are looking for.
There are additional dependencies required when using Squirrel.Windows; see below:
https://www.electron.build/configuration/win

Using <style lang="scss"> in vue component gives error

I am trying to use vue js in rails.
Everything works, except when I tried to use <style> inside .vue component
The exact error is:
./app/javascript/layouts/dashboard.vue?vue&type=style&index=0&lang=scss& (./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js??ref--1-2!./node_modules/style-loader/dist!./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/sass-loader/dist/cjs.js??ref--5-3!./node_modules/vue-loader/lib??vue-loader-options!./app/javascript/layouts/dashboard.vue?vue&type=style&index=0&lang=scss&)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Expected newline.
My environment.js file
const { environment } = require('#rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
const vueLoader = require('./loaders/vueLoader')
const vuetifyLoader = require('./loaders/vuetifyLoader')
environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())
environment.loaders.prepend('vue', vueLoader)
environment.loaders.prepend('vuetify', vuetifyLoader)
const resolver = {
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
environment.config.merge(resolver)
module.exports = environment
VuetifyLoader.js file
module.exports = {
test: /\.s(c|a)ss$/,
use: [
'vue-style-loader',
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^7.0.0
options: {
implementation: require('sass'),
fiber: require('fibers'),
indentedSyntax: true // optional
},
// Requires sass-loader#^8.0.0
options: {
implementation: require('sass'),
sassOptions: {
fiber: require('fibers'),
indentedSyntax: true // optional
},
},
},
],
}
install these two plugins.
npm install --save node-sass
npm install --save sass-loader
So, the problem was with fiber and indentedSyntax. After removing those two, everything works as expected. I was getting lots of error related to scss like
like
expected new line
in sass files inside node_modules. I don't know, why vuetify recommends to use fiber in sass loader.

Intern 2.0: coverage report not generated anymore on Windows (regression)

With Intern revision 1.7, I was able to run node node_modules/intern/bin/intern-client.js config=test/internNode on Windows (Git Bash) and on CentOS (within a VirtualBox VM). If at least one test was failing, the coverage report was not generated.
With Intern revision 2.0, coverage reports are never generated on Windows, only on CentOS. They are now even generated if a test fails...
It does not seem that any of the Intern dependency is platform dependent. Is it possible one has a glitch due to a path just formated for Linux?
A+, Dom
Update with the configuration file:
The module FileScanner retrieves all files matching the given regular expression in the specified folders. It avoids having to document a static list of test files to run.
The test suite runs code to verify both the client logic and the server logic.
.
/*global define*/
define([
'intern/node_modules/dojo/has',
'src/tests/FileScanner'
], function (has, FileScanner) {
'use strict';
has.add('tests-api', true); // To enable entry points for test purposes
has.add('dojo-debug-messages', false); //
var unitTestFiles = new FileScanner.getFiles(['src/client/ubi', 'src/server'], /(?:\w+\/)*\w+Test\.js$/),
functionTestFiles = [];
return {
useLoader: {
'host-node': 'dojo/dojo'
},
loader: {
map: {
'*': {
'dojo/has': 'intern/node_modules/dojo/has',
'dojo/node': 'intern/node_modules/dojo/node',
'dojo/text': 'ubi/utils/tests/dojo/textMock',
'dojo/parser': 'ubi/utils/tests/dojo/parserMock',
'dijit/_TemplatedMixin': 'ubi/utils/tests/dijit/_TemplatedMixinMock',
'dijit/_WidgetBase': 'ubi/utils/tests/dijit/_WidgetBaseMock',
'dijit/_WidgetsInTemplateMixin': 'ubi/utils/tests/dijit/_WidgetsInTemplateMixinMock',
'dijit/_AttachMixin': 'ubi/utils/tests/dijit/_AttachMixinMock',
// To limit side-effects of the GFX library
'dojox/charting/Chart': 'ubi/utils/tests/noopMock',
'dojox/charting/widget/Chart': 'ubi/utils/tests/noopMock',
'dojox/charting/axis2d/Default': 'ubi/utils/tests/noopMock',
'dojox/charting/plot2d/Lines': 'ubi/utils/tests/noopMock',
'dojox/charting/plot2d/Markers': 'ubi/utils/tests/noopMock',
'dojox/charting/plot2d/Pie': 'ubi/utils/tests/noopMock',
'dojox/charting/action2d/Highlight': 'ubi/utils/tests/noopMock',
'dojox/charting/action2d/Magnify': 'ubi/utils/tests/noopMock',
'dojox/charting/action2d/MoveSlice': 'ubi/utils/tests/noopMock',
'dojox/charting/action2d/PlotAction': 'ubi/utils/tests/noopMock',
'ubi/charting/themes/omega': 'ubi/utils/tests/noopMock'
}
},
packages: [{
name: 'dojo',
location: 'src/libs/dojo'
}, {
name: 'dijit',
location: 'src/libs/dijit'
}, {
name: 'dojox',
location: 'src/libs/dojox'
}, {
name: 'ubi',
location: 'src/client/ubi'
}, {
name: 'server',
location: 'src/server'
}, {
name: 'tests',
location: 'src/tests'
}]
},
suites: unitTestFiles,
functionalSuites: functionTestFiles,
excludeInstrumentation: /(?:node_modules|libs|tests)/
};
});
Update with the Gruntfile plugin configuration:
The unitTest variable is fetched with a value given as a parameter to the grunt command
I use it to run one test suite at a time
.
intern: {
'unit-tests': {
options: {
runType: 'client',
config: 'src/tests/internNode',
reporters: ['console', 'lcovhtml'],
reportDir: 'target/code-coverage',
suites: unitTest === null ? [] : [unitTest]
}
}
}
There is a defect in Intern that is causing this issue. A patch to resolve the issue is at https://github.com/theintern/intern/pull/255 and will be landed for Intern 2.1 (and maybe another 2.0 point release).

Resources