AngularDart: How to configure routerProviders / routerProvidersHash for development and production environments? - angular-dart

There is one SO question about same problem. But I can't find production-ready code example how to use routerProviders / routerProvidersHash in real application.
As I understand we need to define two injectors and use one of them depending on compile time environment variable, like shown below.
// File: web/main.dart
// >>> Have to use 2 injectors:
#GenerateInjector([
routerProvidersHash,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injectorDev = self.injectorDev$Injector;
#GenerateInjector([
routerProviders,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injectorProd = self.injectorProd$Injector;
// <<<
void main() {
final env = ServerEnvironment();
if (env.isProduction) {
runApp(ng.AppComponentNgFactory, createInjector: injectorProd);
} else {
runApp(ng.AppComponentNgFactory, createInjector: injectorDev);
}
}
// File: lib/server_environment.dart
enum ServerEnvironmentId { development, production }
class ServerEnvironment {
ServerEnvironmentId id;
static final ServerEnvironment _instance = ServerEnvironment._internal();
factory ServerEnvironment() => _instance;
ServerEnvironment._internal() {
const compileTimeEnvironment = String.fromEnvironment('MC_ENVIRONMENT', defaultValue: 'development');
if (compileTimeEnvironment != 'development') {
id = ServerEnvironmentId.production;
} else {
id = ServerEnvironmentId.development;
}
}
bool get isProduction {
return id == ServerEnvironmentId.production;
}
}
File: build.production.yaml
targets:
$default:
builders:
build_web_compilers|entrypoint:
generate_for:
- web/main.dart
options:
compiler: dart2js
# List any dart2js specific args here, or omit it.
dart2js_args:
- -DMC_ENVIRONMENT=production
- --fast-startup
- --minify
- --trust-primitives
# Build execution
pub run build_runner build --config production --release -o web:build
Is the assumption of having two injectors is the right way to do?
Thank you in advance!

What I would do is make a different main.dart file for your different injector setup. You shouldn't have too much stuff in main.dart it should just serve as a mechanism to start your app. The branching should occur in build.production.yaml as specifying a different main for production (i.e. web/main_production.dart) and this file is the one with the non-hash route provider. This would remove the need for a "ServerEnvironment" and a if/else with a potentially confusing double injector setup in one file.
// File: web/main.dart
#GenerateInjector([
routerProvidersHash,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injector = self.injector$Injector;
void main() {
runApp(ng.AppComponentNgFactory, createInjector: injector);
}
and
// File: web/main_production.dart
#GenerateInjector([
routerProviders,
ClassProvider(Client, useClass: BrowserClient),
])
final InjectorFactory injector = self.injector$Injector;
void main() {
runApp(ng.AppComponentNgFactory, createInjector: injector);
}
with
File: build.production.yaml
targets:
$default:
builders:
build_web_compilers|entrypoint:
generate_for:
- web/main_production.dart
options:
compiler: dart2js
# List any dart2js specific args here, or omit it.
dart2js_args:
- --fast-startup
- --minify
- --trust-primitives
Ran as
# Build execution
pub run build_runner build --config production --release -o web:build

Related

Running "yarn hardhat deploy --tags mocks' to but its running other files. Do i need any specific dependencies? If so how can i check?

This is the file i am trying to deploy for testing, called "00-deploy-mocks":
const { network } = require("hardhat")
const {
developmentChains,
DECIMALS,
initialAnswer
} = require("../helper-hardhat-config")
module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = getNamedAccounts()
const chainId = network.config.chainId
// If we are on a local development network, we need to deploy mocks!
if (developmentChains.includes(network.name)) {
log("Local network detected! Deploying mocks...")
await deploy("MockV3Aggregator", {
contract: "MockV3Aggregator",
from: deployer,
log: true,
args: [DECIMALS, initialAnswer]
})
log("Mocks Deployed!")
log("------------------------------------------------")
}
}
module.exports.tags = ["all", "mocks"]
This is the error im getting:
yarn run v1.22.15
warning package.json: No license field
$ /home/fbaqueriza/hh-fcc/hardhat-fund-me-fcc/node_modules/.bin/hardhat deploy --tags mocks
Nothing to compile
An unexpected error occurred:
Error: ERROR processing skip func of /home/fbaqueriza/hh-fcc/hardhat-fund-me-fcc/deploy/01-deploy-fund-me.js:
/home/fbaqueriza/hh-fcc/hardhat-fund-me-fcc/deploy/01-deploy-fund-me.js:29
const fundMe = await deploy("FundMe", {
^^^^^

EF Core InMemory DB does not apply configurations from assembly and returns no data

I'm trying to test my app with an InMemory DB so I can run Postman tests against it.
I have a docker-compose that successfully starts it:
version: '3.9'
services:
api:
image: ${DOCKER_REGISTRY-}api-test
build:
context: ../
dockerfile: API/Dockerfile
ports:
- 80:80
- 443:443
environment:
- ASPNETCORE_ENVIRONMENT=Test
The test env is setup for the InMemory DB:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"UseOnlyInMemoryDatabase": true
}
I successfully configure the DB service in here:
namespace Infrastructure
{
public static class Dependencies
{
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
{
var useOnlyInMemoryDatabase = false;
if (configuration["UseOnlyInMemoryDatabase"] != null)
{
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]);
}
if (useOnlyInMemoryDatabase)
{
services.AddDbContext<BookDesinerContext>(c =>
c.UseInMemoryDatabase("BookDesignerDB"));
}
else
{
...
}
}
}
}
I get the successful log like this:
info: API[0]
PublicApi App created...
info: API[0]
Seeding Database...
Starting Seed Category
Ended Seeding and applying
warn: Microsoft.EntityFrameworkCore.Model.Validation[10620]
The property 'GameCell.Settings' is a collection or enumeration type with a value converter but with no value comparer. Set a value comparer to ensure the collection/enumeration elements are compared correctly.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
Entity Framework Core 6.0.8 initialized 'BookDesinerContext' using provider 'Microsoft.EntityFrameworkCore.InMemory:6.0.7' with options: StoreName=BookDesignerDB
info: API[0]
LAUNCHING API
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://[::]:80
Notice the log from "Ended Seeding and Applying", which is set in OnModelCreating()
// Seed
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
Console.WriteLine("Ended Seeding and applying");
All my configs seed data like this:
namespace Infrastructure.Data.Seeding
{
public class TagConfig : IEntityTypeConfiguration<Tag>
{
public void Configure(EntityTypeBuilder<Tag> builder)
{
builder.ToTable("Tag");
builder.Property(t => t.Value).IsRequired();
builder.HasData(
new Tag
{
TagId = 1,
Key = "Held",
Value = "Borja"
},
new Tag
{
TagId = 2,
Key = "Genre",
Value = "Pirat"
}
);
}
}
}
But when I access the collection under http://localhost/api/Tags I get []. I can use a REST client to create new resources and read them, but I want my seed data to be applied. Why does the config not apply the values from builder.HasData()?
For the seeding to actually happen, you need a call to:
context.Database.EnsureCreated();
Try:
services.GetRequiredService<BookDesinerContext>().Database.EnsureCreated();

babel enable import of each dir from root without relative

My root dir structure is like so:
src
utils
types
clients
package.json
etc.
my current babel config i run is like:
{
presets: ['#babel/preset-env', '#babel/preset-typescript', '#babel/preset-react', '#babel/preset-flow'],
plugins: ['#babel/plugin-syntax-dynamic-import', '#babel/transform-runtime'],
env: {
build: {
ignore: ['**/*.spec.tsx', '**/*.spec.ts', '**/*.stories.tsx']
}
},
ignore: ['node_modules']
}
How do I allow various /src files directly imports from root. eg.
import { handyFunction } from 'utils'
import { api } from 'clients'
as opposed to doing this relatively:
import { handyFunction } from '../../../utils'
import { api } from '../../../clients'
You can use babel plugin module resolver as mentioned here https://www.npmjs.com/package/babel-plugin-module-resolver.

Deleting test database in Vapor 3

I want to write some integration tests for Vapor 3 server and I need to have clean Postgre database each time I run my tests. How can I achieve this? It seems migrations isn't the right way to go as they've been running once if database doesn't exist yet.
Have a look at https://github.com/raywenderlich/vapor-til/tree/master/Tests
This requires a DB to be running before you run the tests, but it reverts all migrations at the start of each test run, which gives you a clean DB each time. (Specifically here)
There's also a docker-compose.yml in the root directory for spinning up a completely isolated test environment on Linux
I've found a solution that is less resource-intensive, then reverting all migrations every time.
RSpec has a configuration (use_transactional_fixtures) that allows wrapping every test in an SQL transaction. When testing is over it will rollback the transaction and in consequence revert all the changes that happened during testing. Relevant documentation is here.
We can implement a similar solution in Vapor. My example test looks like this.
final class VaporTests: XCTestCase {
var app: Application!
override func setUp() {
super.setUp()
app = try! Application.buildForTesting()
let conn = try! app.requestPooledConnection(to: .psql).wait()
try! conn.simpleQuery("BEGIN TRANSACTION").wait()
try! app.releasePooledConnection(conn, to: .psql)
}
override func tearDown() {
let conn = try! app.requestPooledConnection(to: .psql).wait()
try! conn.simpleQuery("ROLLBACK").wait()
try! app.releasePooledConnection(conn, to: .psql)
super.tearDown()
}
func testExample() throws {
let request = HTTPRequest(method: .GET, url: "my/endpoint/example")
let wrapper = Request(http: request, using: app)
let response = try ExampleController().example(wrapper).wait()
XCTAssertEqual(response, .ok)
}
}
To make sure that I don't encounter issues with concurrency I'm limiting database pool to 1 connection in the test application.
func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
// ... other configurations
let poolConfig = DatabaseConnectionPoolConfig(maxConnections: 1)
services.register(poolConfig)
}
Many thanks to Jakub Jatczak for helping me to find out how this happens in Rails.
Quite late to the party but following way also does the revert and migrate command work. This code does the similar commands as answer given by #0xTim. But I have made use of Console.framework:
Mostly we use a configure.swift file like below:
import FluentPostgreSQL
import Vapor
public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
// Register providers first
try services.register(FluentPostgreSQLProvider())
...
/// Configure commands
var commandConfig = CommandConfig.default()
commandConfig.useFluentCommands()
services.register(commandConfig)
...
/// Configure migrations
services.register { container -> MigrationConfig in
var migrationConfig = MigrationConfig()
try migrate(migrations: &migrationConfig)
return migrationConfig
}
}
Quite late to the party but following code does execute revert and migrate
commands: (I am using Quick and Nimble so beforeSuite. Commented code is there because unless you use above configure.swift you can just uncomment the code and make use of CommandConfig directly.)
import Quick
import Vapor
import Console
import FluentPostgreSQL
...
configuration.beforeSuite {
let console: Console = Terminal()
// var commandConfig = CommandConfig()
// commandConfig.use(RevertCommand(), as: "revert")
// commandConfig.use(MigrateCommand(), as: "migrate")
var config = Config.default()
var env = Environment.testing
var services = Services.default()
do {
// try App.configure(&config, &env, &services)
let container = try Application(config: config, environment: env, services: services)
let commandConfig = try container.make(CommandConfig.self)
let commands = try commandConfig.resolve(for: container).group()
var input = CommandInput(arguments: ["vapor","revert","--all", "-y"])
try console.run(commands, input: &input, on: container).wait()
input = CommandInput(arguments: ["vapor","migrate","-y"])
try console.run(commands, input: &input, on: container).wait()
} catch let error {
console.error(error.localizedDescription)
exit(1)
}
}
For thoses who are seeking another approach that doesnt involve registering new migrations ( and, to me, adding more code complexity ) you can use a Pre-Action script for tests target ( ⌘ + < )
By using a bash script you can create a brand new postgresql database that will be used to build the project for tests only :
# Variables
export IS_TEST=true
export DB_USERNAME="`whoami`"
export DB_DBNAME="BARTENDER_TEST_DB"
#Creating dedicated Postgres DB
echo "deleting & recreating $DB_DBNAME for user $DB_USERNAME"
psql postgres<< EOF
DROP DATABASE "$DB_DBNAME";
CREATE DATABASE "$DB_DBNAME";
\list
EOF
Then in configure.swift file you create a PostgreSQLDatabaseConfig that matches the newly created database
if let _ = Environment.get("IS_TEST") { // IS_TEST is defined only in Pre-Action script
guard let username = Environment.get("DB_USERNAME") else {
fatalError("Failed to create PostgresConfig - DB_USERNAME in Environment variables")
}
guard let databasename = Environment.get("DB_DBNAME") else {
fatalError("Failed to create PostgresConfig - DB_DBNAME in Environment variables")
}
postgresqlConfig = PostgreSQLDatabaseConfig(
hostname: "127.0.0.1",
port: 5432,
username: username,
database: databasename,
password: nil
)
}
else { /* your other config here */ }
let database = PostgreSQLDatabase(config: postgresqlConfig)
...
The big advantage I found in this it that I can even trigger a vapor build and vapor run from another project that will create a brand new Webservice environment for my continuous integration testings, just by inserting the correct environment variables
Simplest way I found was to add PostgresKit to the test target and use it to setup a connection to call my "clean-up" queries.
#testable import App
import Vapor
import XCTest
import PostgresKit
final class UserTests: XCTestCase {
var pools: EventLoopGroupConnectionPool<PostgresConnectionSource>!
var postgresDb: PostgresDatabase!
var eventLoopGroup: EventLoopGroup!
override func setUp() {
let configuration = PostgresConfiguration(
hostname: "localhost",
username: "postgres",
password: "password",
database: "db_name"
)
eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
pools = EventLoopGroupConnectionPool(
source: PostgresConnectionSource(configuration: configuration),
on: eventLoopGroup
)
postgresDb = pools.database(logger: Logger.init(label: "TestLogger"))
}
override func tearDown() {
let _ = try! postgresDb.query("DELETE FROM \(User.schema)").wait()
try! pools.syncShutdownGracefully()
try! eventLoopGroup.syncShutdownGracefully()
}
func testUploadUser() throws {
let app = Application(.testing)
defer { app.shutdown() }
try configure(app)
try app.testable(method: .running).test(.POST, "api/users", beforeRequest: { req in
try req.content.encode(["firstName" : "Dwide", "lastName" : "Shrewd"])
}, afterResponse: { res in
XCTAssertEqual(res.status, .ok)
let user = try res.content.decode(User.self)
XCTAssertEqual(user, User(id: user.id, firstName: "Dwide", lastName: "Shrewd"))
})
}
}
And this is my Package.swift
// swift-tools-version:5.2
import PackageDescription
let package = Package(
name: "MyVaporProject",
platforms: [
.macOS(.v10_15)
],
dependencies: [
// 💧 A server-side Swift web framework.
.package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent.git", from: "4.0.0"),
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"),
.package(url: "https://github.com/vapor/postgres-kit.git", from: "2.0.0")
],
targets: [
.target(
name: "App",
dependencies: [
.product(name: "Fluent", package: "fluent"),
.product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"),
.product(name: "Vapor", package: "vapor")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
.target(name: "Run", dependencies: [.target(name: "App")]),
.testTarget(
name: "AppTests",
dependencies: [
.target(name: "App"),
.product(name: "XCTVapor", package: "vapor"),
.product(name: "PostgresKit", package: "postgres-kit")
]
)
]
)
As in previous answers, this requires a stood-up Postgres database, already migrated, ready to take connections before the tests start.

qbs avr compiling

I try to build simple project with qbs
import qbs
Project {
name: "simple"
Product {
name: "micro"
type: "obj"
Group {
name: "sources"
files: ["main.c", "*.h", "*.S"]
fileTags: ['c']
}
Rule {
inputs: ["c"]
Artifact {
fileTags: ['obj']
filePath: input.fileName + '.o'
}
prepare: {
var args = [];
args.push("-g")
args.push("-Os")
args.push("-w")
args.push("-fno-exceptions")
args.push("-ffunction-sections")
args.push("-fdata-sections")
args.push("-MMD")
args.push("-mmcu=atmega328p")
args.push("-DF_CPU=16000000L")
args.push("-DARDUINO=152")
args.push("-IC:/Programs/arduino/hardware/arduino/avr/cores/arduino")
args.push("-IC:/Programs/arduino/hardware/arduino/avr/variants/standard")
args.push("-c")
args.push(input.fileName)
args.push("-o")
args.push(input.fileName + ".o")
var compilerPath = "C:/Programs/arduino/hardware/tools/avr/bin/avr-g++.exe"
var cmd = new Command(compilerPath, args);
cmd.description = 'compiling ' + input.fileName;
cmd.highlight = 'compiler';
cmd.silent = false;
console.error(input.baseDir + '/' + input.fileName);
return cmd;
}
}
}
}
And I get error
compiling main.c
C:/Programs/arduino/hardware/tools/avr/bin/avr-g++.exe -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD "-mmcu=atmega328p" "-DF_CPU=16000000L" "-DARDUINO=152" -IC:/Programs/arduino/hardware/arduino/avr/cores/arduino -IC:/Programs/arduino/hardware/arduino/avr/variants/standard -c main.c -o main.c.o
avr-g++.exe: main.c: No such file or directory
avr-g++.exe: no input files
Process failed with exit code 1.
The following products could not be built for configuration qtc_avr_f84c45e7-release:
micro
What do I wrong?
File main.c present in project and in directory.
If I start this command from command prompt I do not get error.
In short, you need to pass input.filePath after -c and -o, not input.fileName. There's no guarantee that the working directory of the command invoked will be that of your source directory.
You can set the workingDirectory of a Command object, but that is not generally recommended as your commands should be independent of the working directory unless absolutely necessary.
Furthermore, you appear to be duplicating the functionality of the cpp module. Instead, your project should look like this:
import qbs
Project {
name: "simple"
Product {
Depends { name: "cpp" }
name: "micro"
type: "obj"
Group {
name: "sources"
files: ["main.c", "*.h", "*.S"]
fileTags: ['c']
}
cpp.debugInformation: true // passes -g
cpp.optimization: "small" // passes -Os
cpp.warningLevel: "none" // passes -w
cpp.enableExceptions: false // passes -fno-exceptions
cpp.commonCompilerFlags: [
"-ffunction-sections",
"-fdata-sections",
"-MMD",
"-mmcu=atmega328p"
]
cpp.defines: [
"F_CPU=16000000L",
"ARDUINO=152"
]
cpp.includePaths: [
"C:/Programs/arduino/hardware/arduino/avr/cores/arduino",
"C:/Programs/arduino/hardware/arduino/avr/variants/standard
]
cpp.toolchainInstallPath: "C:/Programs/arduino/hardware/tools/avr/bin"
cpp.cxxCompilerName: "avr-g++.exe"
}
}
it's work
args.push("-c")
args.push(input.filePath) at you args.push(input.fileName)
args.push("-o")
args.push(output.filePath)at you args.push(input.fileName)