Build Electron app using Ionic v5 with #capacitor-community/electron - ionic-framework

I've been sitting last week with the following problem - I wanted to compile my Ionic project not only to android version, but also to electron desktop app. But, every time when I deployed packed electron version, I've got a white screen.
How to reproduce problem:
# i create simple angular app
ionic start example-app tabs --type angular
cd example-app
# i add #capacitor-community version of electron, since the original electron is deprecated
npm i #capacitor-community/electron
# required to get a www folder
ionic build
# add electron folder to project
npx cap add #capacitor-community/electron
# now we work inside electron project...
cd electron
# we can build project
npm run build
# we can start live project
npm run electron:start-live
# and now we have crash - just a blank white window
npm run electron:pack

I've been able to get visible window in deployed version, making the following change inside ./electron/src/setup.ts file. You need to find the following fragment:
// Set a CSP up for our application based on the custom scheme
export function setupContentSecurityPolicy(customScheme: string): void {
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
electronIsDev
? `default-src ${customScheme}://* 'unsafe-inline' devtools://* 'unsafe-eval' data:`
: `default-src ${customScheme}://* 'unsafe-inline' data:`,
],
},
});
});
}
and change it to:
// Set a CSP up for our application based on the custom scheme
export function setupContentSecurityPolicy(customScheme: string): void {
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': [
`default-src ${customScheme}://* 'unsafe-inline' devtools://* 'unsafe-eval' data:`
],
},
});
});
}

Related

gatsby build fails when adding mapbox-gl-geocoder to gatsby.js

I have a gatsby.js application with mapbox-gl and it all worked successfully until I tried to include the mapbox-gl-geocoder package to add search functionality.
I have installed it using npm as the following:
npm install mapbox/mapbox-gl-geocoder --save
then, added it to the React component:
import '#mapbox/mapbox-gl-geocoder/lib/mapbox-gl-geocoder.css';
import MapboxGeocoder from '#mapbox/mapbox-gl-geocoder';
and inside a useEffect hook:
map.addControl(
new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
zoom: 20,
placeholder: 'Enter City',
mapboxgl: mapboxgl
}), 'top-left'
);
locally, when I run gatsby develop it works as it should, but when I deploy it with Netlify, I get the following error:
:24:21 PM: error Generating SSR bundle failed
1:24:21 PM: Can't resolve 'electron' in '/opt/build/repo/node_modules/#mapbox/mapbox-sdk/node_modules/got'
1:24:21 PM: If you're trying to use a package make sure that 'electron' is installed. If you're trying to use a local file make sure that the path is correct.
it seems that mapbox-gl-geocoder has a dependency to #mapbox/mapbox-sdk and the mapbox-sdk has a dependency to got that somehow needs electron ?
The only thing i can read about electron in the got npm page is the following:
Electron support has been removed
The Electron net module is not consistent with the Node.js http module. See #899 for more info.
In any way, I tried to install electron with npm to see if the errors are gone, and the build started to fail with new error indicating that the window object is not available.
10:35:45 AM: error "window" is not available during server side rendering.
Googling that error led me to some answers about not loading the packages in gatsby-node.js but that didn't help either.
When dealing with third-party modules that use window in Gatsby you need to add a null loader to its own webpack configuration to avoid the transpilation during the SSR (Server-Side Rendering). This is because gatsby develop occurs in the browser while gatsby build occurs in the Node server where obviously there isn't a window or other global objects.
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /#mapbox/,
use: loaders.null(),
},
],
},
})
}
}
Keep in mind that the test value is a regular expression that will match a folder under node_modules so, ensure that the /#mapbox/ is the right name.
Using a patch-package may work but keep in mind that you are adding another package, another bundled files which may have a performance effect. The proposed snippet is a built-in solution that happens when you build your application.

Ionic native device plugin #ionic-native/device returns all nulls

I need to do a device detection in my Ionic project so I've installed #ionic-native/device plugin per instructions here: https://ionicframework.com/docs/native/device/
However when I wire it in inside of a component, then run ionic serve to preview changes, console.log returns Device object with all values set to null, same happens when I try to use individual property e.g. this.device.model:
Here is how I use it inside of a component:
import {Device} from "#ionic-native/device";
// ...
#Component({
// ...
})
export class MyComponent {
constructor(private device: Device) {
}
ngOnInit() {
console.log(this.device);
}
}
And I've added it to AppModule as well:
import {Device} from "#ionic-native/device";
// ...
#NgModule({
// ...
providers: [
Device
]
})
export class AppModule() {
}
Cordova device plugin was auto injected into config.xml:
<?xml version='1.0' encoding='utf-8'?>
<widget <!-- ... --> >
<!-- ... -->
<plugin name="cordova-plugin-device" spec="2.0.0" />
</widget>
Here is my Ionic stack (at least packages that should be relevant to the issue):
"#angular/*": "^5.2.4", // all packages
"#ionic-native/*": "4.5.2", // all packages
"#ionic-native/device": "4.5.2"
"ionic-angular": "3.9.2",
"cordova-plugin-device": "2.0.0",
"typescript": "2.6.2"
Thanks!
UPDATE:
I was able to get device details in the browser by running:
cordova run browser
This assumes you have added browser as a platform, if not run:
ionic cordova platform add browser
(From the link in the answer posted by #AndrewLively: https://stackoverflow.com/a/49034015/448816)
If you are running in the browser using ionic serve then most of the ionic-native plugins won't work since it is not treated by ionic as a valid browser platform.
This is not well documented, but is discussed in an issue in the ionic-native repo.
Should see the packages installed and see they are in the same version in "package.json"
Core and Native packages must be in the same version or the native package should not be larger.
The folder "platforms" must be delete
Use these commands
ionic build
ionic cordova platform add browser
cordova run browser
code for .ts
console.log('Device Model is: ' + this.device.model);
And works !

How to remove default assets from ionic 2 build?

I am learning Ionic 2; writing code in Visual Studio code. I created project using following command:
> ionic start --v2 MyFirstIonic blank
And then
> cd MyFirstIonic
> ionic platform add android
When I build and run, > ionic run android, ionic creates assets folder in www directory and copies font files for Ionicons, Roboto, and Noto-sans, which are added in apk during build process. I'd like to exclude Ionicons, Roboto, and Noto-Sans from final build, and use FontAwesome files instead. How will I be able to achieve this?
You need to edit your node_modules/#ionic/app-scripts/copy.config.js.
Sample file here.
Remove copyFonts entry :
copyFonts: {
src: ['{{ROOT}}/node_modules/ionicons/dist/fonts/**/*', '{{ROOT}}/node_modules/ionic-angular/fonts/**/*'],
dest: '{{WWW}}/assets/fonts'
},
from the file. This copies the ionicon fonts to your www folder.
Also remove the assets you do not need from src/assets folder.
You can edit copy.config.js file to add any other assets into the build process.
Refer answers here.
I would suggest you delete the unnecessary files from:
[project]/node_modules/ionic-angular/fonts/
(Keep the ionicons.* files.)
You'll still have to do that every time you update ionic-angular but it's easier and less error prone than keeping track of changes to the app-scripts bundle.
Additionally, comment out the roboto and noto-sans imports in:
[project]/src/theme/variables.scss
--
If you still want to update the script then the right way to do that is to copy the file locally as [project]/src/webpack.config.js and add the following entry to your package.json:
"config": {
"ionic_webpack": "./webpack.config.js"
}
--
Hope that helps!

How can I setup webpack to minify and combine scss and javascript like CodeKit?

I'm having trouble using webpack instead of Codekit v1.9.3. I started working to move from CodeKit to Grunt and Gulp, and then learned about webpack which sounds very cool. I just can't seem to get it working correctly.
"Like Codekit" means I can:
Write javascript with the coffeescript syntax
Have all script source files and libraries minified / uglified and combined into one file
Selectively include components of the bootstrap-sass (scss) framework as needed
Maintain a small file with bootstrap customizations via sass variables, like $brand-primary
Use webpack --watch to compile both scripts and styles automatically when they are changed
End up with one css file and one script file that can be included with a stylesheet and script tag.
Codekit Project Setup
Bower resources:
I'm currently storing these globally, outside of the project:
~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets
Because CodeKit supports compass, I've got this in my config.rb file:
add_import_path "~/bower_components/twbs-bootstrap-sass/vendor/assets/stylesheets"
Project Structure
js/fancybox.js
js/main.js <-- currently the compiled js 'output' file
js/main.coffee
css/styles.css <-- currently the compiled css 'output' file
scss/styles.scss
scss/modules/_bootstrap-customizations.scss
scss/modules/_typography.scss
scss/partials/_header.scss
scss/partials/_footer.scss
Contents of styles.scss
#import "modules/bootstrap-customizations"; # local customizations
#import "bootstrap/variables";
#import "bootstrap/mixins";
... # load bootstrap files as required
#import "bootstrap/wells";
System Setup:
system: OS X 10.9
node - v0.10.32
npm - v2.1.7
zsh - zsh 5.0.7 (x86_64-apple-darwin13.4.0)
node was installed with homebrew's brew install node and seems to be working fine otherwise.
What I've Tried
I've read over these pages:
http://webpack.github.io/docs/configuration.html
https://github.com/petehunt/webpack-howto
http://webpack.github.io/docs/tutorials/getting-started/
https://www.npmjs.org/package/bootstrap-sass-webpack
I've attempted to create a webpack.config.js file several times, my latest attempt was several versions of this:
module.exports = {
entry: [
"./node_modules/bootstrap-sass-webpack!./bootstrap-sass.config.js",
"./js/main.coffee"
],
output: {
path: __dirname,
filename: "main.js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" }
]
}
};
Webpack Error
When I run webpack I get this:
ERROR in ./~/bootstrap-sass-webpack/~/css-loader!/Users/cwd/~/sass-loader!./~/bootstrap-sass-webpack/bootstrap-sass-styles.loader.js!./bootstrap-sass.config.js
stdin:1: file to import not found or unreadable: "~bootstrap-sass/assets/stylesheets/bootstrap/variables
NPM Error
I get an error when attempting to npm install bootstrap-sass, and not had any luck when searching for a solution. I'm not even sure I need this module.
npm ERR! Darwin 13.4.0
npm ERR! argv "node" "/usr/local/bin/npm" "install" "bootstrap-sass"
npm ERR! node v0.10.32
npm ERR! npm v2.1.7
npm ERR! code EPEERINVALID
npm ERR! peerinvalid The package bootstrap-sass does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer bootstrap-sass-webpack#0.0.3 wants bootstrap-sass#~3.2.0
npm ERR! Please include the following file with any support request:
npm ERR! /Users/cwd/webpack-test/npm-debug.log
Sources of Confusion
The most confusing parts of webpack for me are:
Where should things like require("bootstrap-sass-webpack") be added - is it in the webpack.config.js file, or in the js/main.js file?
Should modules like this available to webpack as soon as they are installed with npm install ?
I thought that I should do npm install webpack -g so that webpack was installed globally, and use npm install without the -g for the other modules. However, I don't see any node_modules folder being created in my project. Shouldn't there be one?
How are the search paths determined / specified for things like require("bootstrap-sass-webpack") ?
What node modules should I install to be able to do this? And what should my webpack.config.js look like?
Introduction
Webpack is mainly a JavaScript-bundler. Its "native" language is JavaScript and every other source requires a loader which transforms it to JavaScript. If you require() an html-file for example...
var template = require("./some-template.html");
...you'll need the html-loader. It turns...
<div>
<img src="./assets/img.png">
</div>
...into...
module.exports = "<div>\n <img src=\"" + require("./assets/img.png") + "\">\n</div>";
If a loader doesn't return JavaScript, it needs to be "piped" to another loader.
How to load SASS-files
Configure loaders
In order to use SASS you'll need at least the sass-loader and the css-loader. The css-loader returns a JavaScript string. If you want to import the returned JavaScript string as StyleSheet, you'll also need the style-loader.
Run npm i sass-loader css-loader style-loader --save
Now you need to apply these loaders on all files that match /\.scss$/:
// webpack.config.js
...
module: {
loaders: [
// the loaders will be applied from right to left
{ test: /\.scss$/, loader: "style!css!sass" }
]
}
...
You can also pass options to node-sass as query parameters:
{
test: /\.scss$/, loader: "style!css!sass?includePaths[]=" +
path.resolve(__dirname, "./bower_components/bootstrap-sass/assets/stylesheets/"
}
Since bootstrap references icons via the url() statement, the css-loader will try to include these assets into the bundle and will throw an exception otherwise. That's why you'll also need the file-loader:
// webpack.config.js
...
module: {
loaders: [
{ test: /\.scss$/, loader: "style!css!sass" },
{ test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },
]
}
...
Configure entry
To include bootstrap into your bundle there are several ways. One is via the multi-entry option as you've already tried. I recommend to use a single entry where you require() your main sass-file:
// main.js
require("./main.scss");
Given that your includePaths are configured then you can do:
// main.scss
// Set the font path so that url() points to the actual file
$icon-font-path: "../../../fonts/bootstrap";
#import "bootstrap";
Please note that import statements inside scss-files are not touched by webpack because libsass has no api (yet) to provide custom resolvers.
To prevent code duplication it's also important to have a single main sass-file, because webpack compiles every sass-file individually.
With the coffee-loader installed via npm your final webpack.config.js should look like:
module.exports = {
entry: "./js/main.coffee",
output: {
path: __dirname,
filename: "main.js"
},
module: {
loaders: [
{ test: /\.scss$/, loader: "style!css!sass" },
{ test: /\.jpe?g$|\.gif$|\.png$|\.svg$|\.woff$|\.ttf$/, loader: "file" },
{ test: /\.coffee$/, loader: "coffee" }
]
}
};
Webpack globally?
It's best not to install webpack globally, because it's a dependency of your project and thus should be controlled via npm. You can use the scripts-section of your package.json:
{
...
"scripts": {
"start": "webpack --config path/to/webpack.config.js & node server.js"
}
}
Then you just need to run npm start

Ionic livereload: how to ignore some files?

I have an Ionic project and I use external tool for processing Coffee and SCSS. By default livereload in Ionic project watches everything. Where I can change this?
This setting is named watchPatterns (source) and can be changed in ionic.project file:
{
...
"watchPatterns": ["www/**/*", "!www/lib/**/*", "!www/config.codekit", "!www/**/*.scss", "!www/**/*.coffee"]
}
Default value: ["www/**/*", "!www/lib/**/*"]
I just wanted to give an update as the accepted answer does not work for the newer version of Ionic CLI.
For Ionic CLI v3.1.2 & Ionic Framework v1.3.3:
Versions:
Ionic CLI : 3.1.2
Ionic Framework : ionic1 1.3.3
#ionic/cli-utils : 1.1.2
#ionic/cli-plugin-ionic1 : 1.1.2
The "watch pattern" for livereload is not configurable from your project files. You have to change WATCH_PATTERNS in the source code itself.
If you've built your Ionic v1 app using the tabs starter app (doc):
Example:ionic start myApp tabs --type ionic1
The file you will need to change is in the directory ./myApp/node_modules/#ionic/cli-plugin-ionic1/dist/serve/config.js
Below is what the file will look like:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
exports.WATCH_PATTERNS = [
'scss/**/*',
'www/**/*',
'!www/lib/**/*',
'!www/**/*.map'
];
exports.LOGGER_DIR = '__ion-dev-server';
exports.IONIC_LAB_URL = '/ionic-lab';
exports.DEFAULT_ADDRESS = '0.0.0.0';
exports.DEFAULT_LIVERELOAD_PORT = 35729;
exports.DEFAULT_SERVER_PORT = 8100;
exports.IOS_PLATFORM_PATH = path.join('platforms', 'ios', 'www');
exports.ANDROID_PLATFORM_PATH = path.join('platforms', 'android', 'assets', 'www');
From there you can modify the WATCH_PATTERNS array to watch or '!' not watch a particular directory or file.
This isn't an ideal solution since the starter app uses the Node Package Manager (NPM) to manage the #ionic/cli-plugin-ionic1 dependency. If you decide to run this project on another computer or update your node modules, then you would have to re-do the steps above to customize the watch patterns. However, you can fork the source code and tell NPM to use your version instead.