Microservices monorepo w/ Prettier & linting - microservices

I have a project with 4 microservices in total, 3 in PHP and 1 in JS, in 1 monorepo. I love to use Prettier for both languages and I want to use ESLint for JS and CS Fixer for PHP to assure code quality. Right now I have a Prettier installation and configuration for each package.
/js1
/.eslintrc.json
/prettier.config.json
/js2
/.eslintrc.json
/prettier.config.json
/js3
/.eslintrc.json
/prettier.config.json
/php1
/prettier.config.json
For the JS packages theres quite some overlap in the configuration. However, there're also specific plugins or settings for Prettier per microservice. The same goes for ESLint for the JS microservices.
I'm thinking about how to
Run Prettier, ESlint and PHPfixer from the root of the project.
Share the configuration, but have microservice-specific config as well.
Optimally run the formatting and linting on staged files as well.
Every solution I found focusses on a frontend-only project and tools like Lerna are not maintained well.
I thought about the following approaches
Use NPM workspaces to install Prettier once on the root, but where do I install Prettier and where its Plugins?
Add Prettier / ESLint scripts to the root packages.json and run them with concurrently (package).
Have a base Prettier config for JS and PHP, extend them in the project directories.
I'm very unclear about what the best practice is, so please share articles, opinions or tools with me.

Related

Why and when does yarn decide not to hoist a package in a workspace?

I'm working on a large project using yarn workspaces. I know that yarn workspaces essentially does two things
It automates the symlinking process we had to do manually years ago when we want to share private packages
It hoists all similar packages at the top in node_modules in order to be more efficient.
However, I have noticed that my packages still contain code in their own node_modules and I'm not sure why. When I make a sample monorepo app and say I install lodash in one, it goes straight to the root node_modules.
Why and when does yarn decide to install a package inside a package's node_modules ?
I found the answer on yarn's Discords. yarn will always hoist unless it would conflict with another version.

lerna advantage with yarn workspaces, why use lerna at all

I'm trying to setup a mono repo and came across lerna+yarn. My problem is, what is the actual advantage I get in using lerna. I can use yarn workspaces only and have the same functionality. I came across the following Are there any advantages to using Lerna with Yarn workspaces? but here there is no specific answer as to the specific advantage of using lerna.
as stated in the yarn workspaces documentation,
workspaces are the primitives that tools like lerna can use
You might have a project that only needs workspaces as "primitives", and not lerna. Both are tools, but lerna as a higher-level-tool than yarn workspaces helps you organize your monorepo when you are working on open source or in a team:
The install (bootstrap) / build / start-scripts are at the project root:
meaning one install and package resolution instead of one for each package
node_modules at the root is 'fat', in sub-projects it's tiny: One place to look for when you resolve package conflicts
parallel execution of scripts in sub-projects: E.g. starting up both server and frontend development in watch-mode can just be one command
publishing and versioning is much easier
There is certainly a lot of overlap between the two. The big difference is that Lerna handles package management, versioning and deployment.

NPM caching similar to a local Maven cache

Gradle's dependency management system stores downloaded artifacts in a local Maven cache. When a build requests that same dependency again the dependency is simply retrieved from the cache, avoiding any network transfer of the artifact.
I'm trying to replicate this behavior with NPM for building JavaScript projects. I was expecting NPM to support a global node_modules cache, but installing a package "globally" in NPM has a different meaning => the package is added to PATH so that it can be used as a CLI tool.
Reading the documenation for npm install, the standard behavior is to install packages into a local node_modules directory. But this would mean many duplicated packages on the system wasting valuable disk space. It also poses a problem for doing clean production builds, since ideally the node_modules should be blown away each time.
Does NPM support something like the Gradle's Maven caching? Documentation on NPM cache doesn't make it any clearer how this is to be used. What's more, it's not obvious if a caching strategy with NPM is safe across multiple parallel builds.
This seems like such a basic requirement for busy CI environments that it must have been solved before. I found the npm-cache tool which seems to offer this support, but it would be much better if caching was supported natively in npm itself.
Thanks!
IMHO it is a pity that the makers did not learn from things like maven that have already been there. If you are doing microservices and have many apps on your machine and you might also have multiple branches or a local jenkins you will have each dependency N*M times on the disk what is an extraordinary waste of disc-space and performance. So you have to be aware that Java or .NET/C# are mature ecosystems while the JavaScript ecosystem is still in the childhood with lots of flaws and edges. But JavaScript is evolving fast so lets hope for the best. Feel free to discuss your pain with the npm makers (https://github.com/npm/npm/issues/).
However, a partial cure comes if you go away from npm and switch to yarn: http://yarnpkg.com/
NPM Cache already comes bundled with NPM out of the box(listed under cli commands). And its main utility is to avoid the network transfer of the same package over and over.
Regarding the duplicate packages issue, as of npm v3 there has been an effort in terms of finding ways to deduplicate dependencies. But it still does not work exactly like Gradle since it is still possible to end up with duplicates of the same package in your node_modules folder.
Per NPM documentation:
Your node_modules directory structure and therefore your dependency tree are dependant on install order
Although a fresh npm install from the same package json always produces the same dependency tree:
The npm install command, when used exclusively to install packages from apackage.json, will always produce the same tree. This is because install order from a package.json is always alphabetical. Same install order means that you will get the same tree.
So at least there is a way to get consistent dependency trees, albeit there's no guarantee it will be the most efficient one. At least those differences do not interfere correct functioning of NPM.
Hope that helps.

Spring boot, maven, AngularJS 2, typescript and live reload

I am in a study phase for an application development. The server-side development has already started, with Spring boot and Maven. Now, I am studying the possible options to develop the client-side.
I'd like to use Angular 2 (I know it's still in alpha), but I'm really hesitating between its javascript and typescript version. I know the live reload with javascript version should work well with maven spring-boot run (in theory), and this is a great help for productivity. I was wondering if there was a way to have the live reload for typescript version of Angular too. Has anyone managed to implement it in its own project? If yes, how did you do?
I have not found any doc about this on maven-typescript-plugin
The build system will be Maven for client side too.
EDIT: Is there an easy way for typescript debugging, or is it a pain?
One way could be adding a watch to automatically be triggered on any file change. For example, try adding the following to your package.json file:
{
"scripts": {
"tsc": "tsc -p src -w"
}
}
As the Quickstart for Angular 2 (literally) states that this will be activated when you open a terminal window in the root of the application folder and enter:
npm run tsc
The script sets the compiler watch option (-w) so the compiler stays alive when it's finished. It watches for changes to .ts files and recompiles them automatically.
Considering this will spit out plain-old .js files, you can use the tooling you're comfortable with to reload the page.

How to reduce duplication of similar build configurations?

I have several projects that I'd like to have in separate build configurations with slightly different configurations:
VCS source and build triggers (i.e. the only difference is which subdirectory of the projects root dir to use)
build steps (the first few are the exact same, but the last few may vary depending on how the unit tests are to be run, dependencies, etc.)
That's it. I looked into Build Configuration Templates, but it seems that does not allow the flexibility of specifying custom build steps or extra VCS roots.
Really I'm just looking to not have to manually copy the (several) build steps from our initial project's build configuration into several more configurations, and to have to maintain them all when things change. It seems there should be a better solution?
I've wondered this as well, but the bits I've found online suggest you favor the redundancy instead of trying to reuse one configuration across your multiple branches or projects.
However, all of that was before version 8 was released, which introduces the ability to extract a meta-runner
Their blog from April 13, 2013 provides a good summary of what they are and how they differ from templates.
Meta-runner
Meta Runner is a powerful feature providing a promising new way for customizing TeamCity and making it even more people-oriented. To understand it, let’s consider an example.
Imagine you have some repeated task used over and over again across different build configurations. The task is defined as one or more build steps, based on built-in runners, like Ant or command line. Most likely you’d want to reuse this task easily across several build configurations. You can’t do this with templates because template enforces you to share the same settings across different configurations which is not always possible. A solution which we propose is to extract Meta-runner out of these steps, see how it works in release notes.
I have yet to implement this, but I will be testing it out soon. It makes me think that you should be able to pass the repository in as a parameter, but I am not sure.
I've been struggling with this for a while and developed a tool to manage it, I call it Dictator Builder.
For a long time, we have been working with "template"-projects. Basically it is a repository that has a fully working application complete with all build configurations needed. Much like react-boilerplate is. We have several template projects, one for each type of application we develop.
Problem with this is keeping copied code in synk with the template project.
I now have the template code packaged within a "dictator". Like this:
https://github.com/tomasbjerre/dictator-react-boilerplate/tree/master/dictatables/static-files/react-boilerplate
The dictator dictates that some static files should be copied to the root of a dictated folder.
{
"message": "Copy react-boilerplate",
"actions": [
{
"copyFrom": "react-boilerplate",
"target": "."
}
]
}
The dictator can be run from command line like npx dictator-react-boilerplate#version. It will dictate the current working directory, typically your code base in an application. It can be configured by the code base in a .dictatorconfig.json file. Perhaps choose not to be dictated on some parts:
{
"ignore": [
"/app",
"/package.json",
"/package-lock.json",
"/Changelod.md"
]
}
So that most of the build configuration from the template is just copied to the dictated code base. And the app folder, and other things, are still managed by the code base.
When cloned, the folder looks like:
app
coverage
.dictatorconfig.json
docs
.gitignore
internals
LICENSE.md
node_modules
package.json
README.md
server
And after npm install, or after npx dictator-react-boilerplate#version it looks like:
.all-contributorsrc
app
appveyor.yml
babel.config.js
Changelog.md
CODE_OF_CONDUCT.md
CONTRIBUTING.md
coverage
.dictatorconfig.json
docs
.editorconfig
.eslintrc.js
.gitattributes
.gitignore
internals
jest.config.js
LICENSE.md
node_modules
.nvmrc
package.json
package-lock.json
.prettierignore
.prettierrc
README.md
server
.stylelintrc
.travis.yml

Resources