Scaling Frontend Systems: Enforcing Standards Without Being a Bottleneck

“Scaling Frontend Systems” is a series of real-world engineering stories from the trenches of frontend development - focused on architectural migrations, testing overhauls, developer experience improvements, and lessons from operating frontend platforms at scale.
Lint + format allows us to enforce a certain code style. Also important is the choice of editor that will have support for the shared rules. We agreed on using Vscode, and for related tooling, we chose typescript, eslint, prettier and editorconfig.
Personally I am not in favour of adding pre-commit hooks as it seems to delay a commit for me. I prefer compilation errors (and possible runtime errors) to be caught during development with typescript.
Vscode has a very good support for typescript and it shows all errors inline. And in webpack I fail compilation when there is a type error using ForkTsCheckerWebpackPlugin like this:
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
// webpack plugins array
plugins: [
new ForkTsCheckerWebpackPlugin({
typescript: {
diagnosticOptions: {
semantic: true,
syntactic: true
},
mode: 'write-references'
}
})
]
As for the formatting, I am using prettier and setup Vscode to format on save. This setting will also be propagated as code using workspace settings. At the same time, to execute these changes, Vscode needs the necessary plugins and we want to make it easier for new developers to onboard into the project. This was done using the recommended extensions settings.
Here is how the .prettierrc
file looks like:
{
"semi": true,
"tabWidth": 2,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "none",
"bracketSameLine": false,
"singleAttributePerLine": true,
"jsxSingleQuote": true
}
And the .eslintrc.js
powering the lint process.
module.exports = {
env: {
es2021: true,
browser: true,
node: true
},
parser: '@typescript-eslint/parser',
plugins: ['import', 'prettier', '@typescript-eslint', 'react'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:promise/recommended',
'plugin:jest/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended'
],
rules: {
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
'jest/no-conditional-expect': 'off',
'jest/expect-expect': [
'error',
{
assertFunctionNames: ['expect*']
}
],
'no-prototype-builtins': 'off',
'promise/always-return': 'off',
'promise/catch-or-return': 'off',
'react-hooks/exhaustive-deps': 'error',
'prettier/prettier': ['warn'],
'no-console': 'error'
},
settings: {
react: {
version: 'detect'
},
'import/resolver': {
alias: {
map: [['@', './src']],
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json']
}
}
},
overrides: [
{
files: ['*.test.{ts,tsx}'],
parserOptions: {
project: 'tsconfig.json',
ecmaVersion: 'latest',
sourceType: 'module',
tsconfigRootDir: __dirname
}
}
]
};
And finally the .vscode/settings.json
{
// tell the ESLint plugin to run on save
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "always"
},
"[javascript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"files.insertFinalNewline": true
}
and .vscode/extensions.json
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
]
}
This is how it feels now after all the auto format in place
And a final step: format the entire project. All the format changes went in a single commit so that it is easier to review. I had also requested for a downtime from my team so that there are no work in progress changes.
—
Once all of this was setup, I added a verify-frontend
step to our CI pipeline that runs the lint and then build. Typecheck happens a sideeffect of the build process as we already have the ForkTsCheckerWebpackPlugin
setup.
As soon as this pull request got merged, all changes going forward would be subject to our standard lint rules and formatted automatically as they are saved. No more formatting related review comments :)
If you’ve faced similar challenges or have insights to share, I’d love to hear from you. Your experiences can enrich this discussion and help others navigating similar paths.
PS: I have setup a simple github repo for my personal reference in the future. If you want, feel free to use it for your own projects.
Subscribe to my newsletter
Read articles from Rohan Bagchi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
