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.
Related
I have a single file Dart program - let's say main.dart. I'm trying to provide some compile time environment values to it using --dart-define=env=env_value but in the Dart program, I'm always getting the default values.
This is what my Dart program looks like
void main() {
const myValue = const String.fromEnvironment("MY_VALUE", defaultValue: "DEFAULT");
print('My value: $myValue'); // Always prints "DEFAULT"
}
This is the command I'm using to run my program
dart main.dart --dart-define=MY_VALUE=SOME_VALUE
Now, when I include the exact same code from above in a Flutter app and run it with the below command, everything seems to work as expecetd but for some reason the above program always prints DEFAULT as the output on console.
flutter run --dart-define=MY_VALUE=SOME_VALUE
Is there something I'm missing when it comes to providing these values in a Dart program? I'm running macOS if that helps in any way.
If you type:
dart --help --verbose
It will give you the list of supported flags.
Usage: dart [<vm-flags>] <dart-script-file> [<script-arguments>]
Executes the Dart script <dart-script-file> with the given list of <script-arguments>.
Supported options:
...
--define=<key>=<value> or -D<key>=<value>
Define an environment declaration. To specify multiple declarations,
use multiple instances of this option.
...
So it appears that the flag you want is --define or -D, rather than --dart-define. Also note that this is considered a "vm-flag" and must come before the file name in order to work.
Therefore the following command should work:
dart --define=MY_VALUE=SOME_VALUE main.dart
I h got an issue with the following serverless config.
this is my handler and the files/folders structure.
the issue is that after uploading my project to AWS when I test my lambda I got an error as follows:
lambda execution fails: "errorMessage": "Unable to import module 'app_monitor': No module named 'monitoring'"
{
"errorMessage": "Unable to import module 'src/app_monitor': No module named 'monitoring'",
"errorType": "Runtime.ImportModuleError",
"requestId": "bca3f67d-815f-452b-a2a6-c713ad2c6baa",
"stackTrace": []
}
have you got any clue how can I add this into serverless config.?
First, a quick tip on troubleshooting: When I ran into such issues it was helpful to go to the AWS console, look at the lambda function, and see what the uploaded file structure looks like on that end. Is the monitoring folder there?
Moreover, in order to specify how a specific function is packaged, you have to explicitly state that you want it to be individually packaged and not follow the general rules of the project as a whole.
You should try to add:
app_monitoring:
package:
individually: true
patterns:
- 'src/**'
More documentation on packaging configuration here
You may also have better luck with explicitly stating the patterns you need, I know I've had issues with globs in the past. So for example you can try:
patterns:
- 'src/app_monitoring.py'
- 'src/monitoring/get_lb.py'
I'm new to dart, and following the tutorial provided on the Dart for the web page.
It all makes sense - apart from one piece of sytax:
final InjectorFactory injector = self.injector$Injector;
Here's the full code from the tutorial:
import 'main.template.dart' as self;
const useHashLS = false;
#GenerateInjector([
routerProvidersHash,
ClassProvider(Client, useClass: InMemoryDataService),
// Using a real back end?
// Import 'package:http/browser_client.dart' and change the
above to:
// ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injector = self.injector$Injector;
void main() {
runApp(ng.AppComponentNgFactory, createInjector: injector);
}
I'm a confused by the apparent .method$Class syntax. Can anyone explain to me what this means/what it's doing?
It's also underlined in Webstorm with the message The getter 'injector$Injector' isn't defined for the class 'self'. Regardless, it runs fine and works as expected.
Thanks in advance!
$ in an identifier has no special meaning. It's by convention often used for names in generated code.
Angular also uses code generation and the code will only become available after code generation was executed for example by webdev serve or webdev build.
I don't know the current state but the code might still be generated in a directory that is not analyzed by the DartAnalyzler and you might always see the error even wen the app can be run without problems.
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.
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