Difference between methods of determining debug or release in Dart - dart

I am aware of two methods of determining whether my app is in running in debug mode:
const bool.fromEnvironment("dart.vm.product") returns true if release.
And this from the Sentry part of the Flutter docs:
bool get isInDebugMode {
// Assume we're in production mode
bool inDebugMode = false;
// Assert expressions are only evaluated during development. They are ignored
// in production. Therefore, this code will only turn `inDebugMode` to true
// in our development environments!
assert(inDebugMode = true);
return inDebugMode;
}
Are those two always equivalent or are there situations where they would give different answers? Which should I use? The first method being compile time seems to favour it.

In general they should be the same, but there can be differences.
const bool.fromEnvironment("dart.vm.product") depends on release build being performed. I haven't checked if profile build returns true or false
assert(inDebugMode = true); depends on asserts being enabled.
asserts are enabled in debug mode by default and disabled in release builds by default but there should be a way to enable/disable asserts independently of release/debug mode, but I haven't found how. Perhaps it's not exposed in Flutter or it is not implemented in Dart yet.
I'd think bool.fromEnvironment() works better with tree-shaking because it can be used to create a const value.

Related

How to log with stacktrace and not show in release version?

I tried to handle exception like this.
try {
// some functions that likely to throw error
} catch (e) {
print(e);
}
but this print(e) didn't tell me where error come from, it only tell me what error is.
I want to know where error come from and have links that navigate to that line. like this
I also don't want to log on release version, so print is not my anwser.
Can you please give any example on how to do this?
There's a couple of options here depending on whether or not you'll want to be able to control logging output throughout your application or if this is a one-off situation.
Solution 1: make use of asserts
In Dart, assert(...) invocations are only included in debug builds (e.g. processes started via flutter run or dart --enable-asserts foo.dart). You can utilize this fact to conditionally execute code depending on whether or not your program is running in release by doing the following:
assert(() {
print('debug-only logging');
}());
Solution 2: use package:logging
A more general solution is to use package:logging to set up a global Logger instance and then only log through that interface. This package lets you write logs with different verbosities and the level property of Logger can be used to determine which log levels are actually printed. This can be combined with solution #1 to conditionally enable logging throughout the application only while debugging:
void main() {
// Disable logs by default.
myLogger.level = Level.OFF;
assert(() {
// Enable logs in debug mode.
myLogger.level = Level.ALL;
}());
// Your logic here
// ...
}

Electron: difference between process.defaultApp and app.isPackaged

What is a the difference between Electron flags process.defaultApp and app.isPackaged? Both are used to distinguish dev and production environment. My observation is that Boolean(process.defaultApp) == !app.isPackaged always. Are there any cases, when both are true or both are false?
From doc and code:
process.defaultApp
A Boolean. When app is started by being passed as parameter to the default app, this property is true in the main process, otherwise it is undefined.
app.isPackaged
A Boolean property that returns true if the app is packaged, false otherwise. For many apps, this property can be used to distinguish development and production environments.
From the code - app.isPackaged is set when exec file is not electron or electron.exe.
Note: I know a minor difference is that process.defaultApp may be used in the main process only.
Both can yield the same result, but some extra care has to be taken for the process.defaultApp property:
handle the case where it is undefined (by using the ! operator for instance)
make use of remote.process instead of process in a renderer process
Main process
var isPackaged = !process.defaultApp;
is equivalent to:
var isPackaged = require('electron').app.isPackaged;
Renderer process
var isPackaged = !require('electron').remote.process.defaultApp;
is equivalent to:
var isPackaged = require('electron').remote.app.isPackaged;
Edit:
Some extra information, although not 100% crystal clear, about why the app.isPackaged property had to be added can be found in the related pull request's conversation: add app.isPackaged #12656

What source code in Dart language can be considered as valid and why?

This script (source code) can be perfectly executed in the production mode.
void main() {
int greeting = "Hello world!";
print(greeting);
}
This is a traditional hello world example that works fine in Dart.
The result is "Hello world!".
This script is self enough because not required other functionality and it works as expected.
Now I have small questions:
Can I consider that this script is valid and correct source code in Dart language becuase it works as expected?
If this script is valid source code in Dart language then why it cannot be executed in non-production mode?
If some code that can be perfectly executed in the production mode but cannot be executed in other mode then which mode in Dart more correct (production mode or other mode)?
P.S.
As a programmer, I am interesting not in theory and practice but I have interest only in answers in my small questions based on real example (even if it are very small).
If my questions are not so correct then I would like to know why?
Because they are directly related to programming in Dart language.
It is valid because types are ignored in production mode.
In checked mode (intended for development only) types are checked and you get an exception.
Types in Dart are not for runtime but for development time to make tools able to reason about the code and show possible bugs.
This means it doesn't matter if you type String or var. You cannot omit it completely because this violates the syntax.
It can be executed in production mode
# ~/dart/playground/bin/dart_valid
$ dart main.dart
Hello world!
It fails in checked mode (development mode)
# ~/dart/playground/bin/dart_valid
$ dart -c main.dart
Unhandled exception:
type 'String' is not a subtype of type 'int' of 'greeting'.
#0 main (file:///home/zoechi/source/my/dart/playground/bin/dart_valid/main.dart:2:18)
#1 _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:216)
#2 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:115)
pub build fails because it uses the analyzer which utilizes type annotations like in checked mode and throws.

Dart: How to use different settings in debug and production mode?

Are there any ideas how I can setup my Dart app to use different settings in debug mode (running in Dartium) and production mode?
For example, I'm using PouchDb in my app, that replicates the database to a particular CouchDb instance, given by an url: db.replicateTo(url);
In debug mode, I would like to use another CouchDb instance (another url) than in production mode.
So, are there any ideas or approaches, to use different setups in both modes?
this works since a short while:
transformers: # or dev_transformers
- $dart2js:
environment: { PROD: "true" }
access it from the code like
String.fromEnvironment()
main() {
print('PROD: ${const String.fromEnvironment('PROD')}');
// works in the browser
// prints 'PROD: null' in Dartium
// prints 'PROD: true' in Chrome
}
see also
Configuring the Built-in dart2js Transformer
How to achieve precompiler directive like functionality
https://github.com/dart-lang/pub/issues/798
http://blog.sethladd.com/2013/12/compile-time-dead-code-elimination-with.html
https://api.dartlang.org/stable/1.22.0/dart-core/bool/bool.fromEnvironment.html
dart check if is building

How to achieve precompiler directive like functionality

I'm developing an angular app, and it's recommended to use generated code for a lot of things running in production, namely template caches, expression caches, and a static DI injector. There's currently no nice way to switch between different build configurations, so I'm using the pattern recommended here:
In lib/main.dart you can see initializer-prod.dart file being imported, which has initializer-dev.dart counterpart. Switching between those two file will allow you to switch between prod and dev modes. You will need to run the generator script before using the prod mode.
This results in the following import:
//import 'initializer_prod.dart' as init; // Use in prod/test.
import 'initializer_dev.dart' as init; // Use in dev.
As you can see, switching the import is a manual process. Is there a better, more automatic way to achieve this?
I see two possibilities (haven't tried any of these myself yet)
one is to use a transformer (see also Pass custom parameters to a dart application when using pub serve to run it)
or
Compile-time dead code elimination with dart2js
Recently a feature should have been added that pub build allows adding an environment variables using a command line option (like dart2js's -d)
log(String msg) {
if (const String.fromEnvironment('DEBUG') != null) {
print('debug: $msg');
}
}
main() {
log('In production, I do not exist');
}
Some links about transformers:
Can We Build It? Yes, We Can!
Assets and Transformers
Day 992: Search and Replace Dart Transformer to Hide from Polymer
Dart Transformers for Polymer Cleanup
Pub transformers
dart2js_dransformer.dart
Document user-defined transformers
EDIT
I was able to configure dart2js options in pubspec.yaml like
transformers:
- $dart2js:
commandLineOptions: [-DDEBUG=true]
environment:
DEBUG: "true"
suppressWarnings: true
terse: true
They are validate and pub build fails if an unknown option is provided or if it's not the expected format (yaml list for commandLineOptions, yaml map form environment)
BUT String.fromEnvironment() didn't get a value
According to this issue, this is supported:
Passing in arguments to dart2js during pub build
I filed a bug How to pass options to dart2js from pubspec.yaml
EDIT-2
I tried it and it is working now:
transformers: # or dev_transformers
- $dart2js:
environment: { PROD: "true" }
access it from the code like
String.fromEnvironment()
main() {
print('PROD: ${const String.fromEnvironment('PROD')}');
// works in the browser
// prints 'PROD: null' in Dartium
// prints 'PROD: true' in Chrome
}
see also Configuring the Built-in dart2js Transformer
EDIT-3
Another way is to use assert to set variables.
assert is ignored in production.

Resources