1
0
mirror of https://github.com/kamranahmedse/developer-roadmap.git synced 2025-08-23 09:22:52 +02:00

Add forntend performance content

This commit is contained in:
Kamran Ahmed
2023-01-24 18:36:14 +04:00
parent 190c75cebe
commit dd7c0ec003
54 changed files with 2021 additions and 807 deletions

View File

@@ -0,0 +1,163 @@
const fs = require('fs');
const path = require('path');
const CONTENT_DIR = path.join(__dirname, '../content');
// Directory containing the best-practices
const BEST_PRACTICE_CONTENT_DIR = path.join(__dirname, '../src/best-practices');
const bestPracticeId = process.argv[2];
const allowedBestPracticeId = fs.readdirSync(BEST_PRACTICE_CONTENT_DIR);
if (!bestPracticeId) {
console.error('bestPractice is required');
process.exit(1);
}
if (!allowedBestPracticeId.includes(bestPracticeId)) {
console.error(`Invalid best practice key ${bestPracticeId}`);
console.error(`Allowed keys are ${allowedBestPracticeId.join(', ')}`);
process.exit(1);
}
// Directory holding the best parctice content files
const bestPracticeDirName = fs
.readdirSync(BEST_PRACTICE_CONTENT_DIR)
.find((dirName) => dirName.replace(/\d+-/, '') === bestPracticeId);
if (!bestPracticeDirName) {
console.error('Best practice directory not found');
process.exit(1);
}
const bestPracticeDirPath = path.join(BEST_PRACTICE_CONTENT_DIR, bestPracticeDirName);
const bestPracticeContentDirPath = path.join(
BEST_PRACTICE_CONTENT_DIR,
bestPracticeDirName,
'content'
);
// If best practice content already exists do not proceed as it would override the files
if (fs.existsSync(bestPracticeContentDirPath)) {
console.error(`Best Practice content already exists @ ${bestPracticeContentDirPath}`);
process.exit(1);
}
function prepareDirTree(control, dirTree, dirSortOrders) {
// Directories are only created for groups
if (control.typeID !== '__group__') {
return;
}
// e.g. 104-testing-your-apps:other-options
const controlName = control?.properties?.controlName || '';
// e.g. 104
const sortOrder = controlName.match(/^\d+/)?.[0];
// No directory for a group without control name
if (!controlName || !sortOrder) {
return;
}
// e.g. testing-your-apps:other-options
const controlNameWithoutSortOrder = controlName.replace(/^\d+-/, '');
// e.g. ['testing-your-apps', 'other-options']
const dirParts = controlNameWithoutSortOrder.split(':');
// Nest the dir path in the dirTree
let currDirTree = dirTree;
dirParts.forEach((dirPart) => {
currDirTree[dirPart] = currDirTree[dirPart] || {};
currDirTree = currDirTree[dirPart];
});
dirSortOrders[controlNameWithoutSortOrder] = Number(sortOrder);
const childrenControls = control.children.controls.control;
// No more children
if (childrenControls.length) {
childrenControls.forEach((childControl) => {
prepareDirTree(childControl, dirTree, dirSortOrders);
});
}
return { dirTree, dirSortOrders };
}
const bestPractice = require(path.join(__dirname, `../public/jsons/best-practices/${bestPracticeId}`));
const controls = bestPractice.mockup.controls.control;
// Prepare the dir tree that we will be creating and also calculate the sort orders
const dirTree = {};
const dirSortOrders = {};
controls.forEach((control) => {
prepareDirTree(control, dirTree, dirSortOrders);
});
/**
* @param parentDir Parent directory in which directory is to be created
* @param dirTree Nested dir tree to be created
* @param sortOrders Mapping from groupName to sort order
* @param filePaths The mapping from groupName to file path
*/
function createDirTree(parentDir, dirTree, sortOrders, filePaths = {}) {
const childrenDirNames = Object.keys(dirTree);
const hasChildren = childrenDirNames.length !== 0;
// @todo write test for this, yolo for now
const groupName = parentDir
.replace(bestPracticeContentDirPath, '') // Remove base dir path
.replace(/(^\/)|(\/$)/g, '') // Remove trailing slashes
.replace(/(^\d+?-)/g, '') // Remove sorting information
.replaceAll('/', ':') // Replace slashes with `:`
.replace(/:\d+-/, ':');
const humanizedGroupName = groupName
.split(':')
.pop()
?.replaceAll('-', ' ')
.replace(/^\w/, ($0) => $0.toUpperCase());
const sortOrder = sortOrders[groupName] || '';
// Attach sorting information to dirname
// e.g. /best-practices/frontend-performance/content/internet
// ———> /best-practices/frontend-performance/content/103-internet
if (sortOrder) {
parentDir = parentDir.replace(/(.+?)([^\/]+)?$/, `$1${sortOrder}-$2`);
}
// If no children, create a file for this under the parent directory
if (!hasChildren) {
let fileName = `${parentDir}.md`;
fs.writeFileSync(fileName, `# ${humanizedGroupName}`);
filePaths[groupName || 'home'] = fileName.replace(CONTENT_DIR, '');
return filePaths;
}
// There *are* children, so create the parent as a directory
// and create `index.md` as the content file for this
fs.mkdirSync(parentDir);
let readmeFilePath = path.join(parentDir, 'index.md');
fs.writeFileSync(readmeFilePath, `# ${humanizedGroupName}`);
filePaths[groupName || 'home'] = readmeFilePath.replace(CONTENT_DIR, '');
// For each of the directory names, create a
// directory inside the given directory
childrenDirNames.forEach((dirName) => {
createDirTree(
path.join(parentDir, dirName),
dirTree[dirName],
dirSortOrders,
filePaths
);
});
return filePaths;
}
// Create directories and get back the paths for created directories
createDirTree(bestPracticeContentDirPath, dirTree, dirSortOrders);
console.log('Created best practice content directory structure');

28
bin/readme.md Normal file
View File

@@ -0,0 +1,28 @@
## CLI Tools
> A bunch of CLI scripts to make the development easier
## `roadmap-links.cjs`
Generates a list of all the resources links in any roadmap file.
## `compress-jsons.cjs`
Compresses all the JSON files in the `public/jsons` folder
## `roadmap-content.cjs`
This command is used to create the content folders and files for the interactivity of the roadmap. You can use the below command to generate the roadmap skeletons inside a roadmap directory:
```bash
npm run roadmap-content [frontend|backend|devops|...]
```
For the content skeleton to be generated, we should have proper grouping, and the group names in the project files. You can follow the steps listed below in order to add the meta information to the roadmap.
- Remove all the groups from the roadmaps through the project editor. Select all and press `cmd+shift+g`
- Identify the boxes that should be clickable and group them together with `cmd+shift+g`
- Assign the name to the groups.
- Group names have the format of `[sort]-[slug]` e.g. `100-internet`. Each group name should start with a number starting from 100 which helps with sorting of the directories and the files. Groups at the same level have the sequential sorting information.
- Each groups children have a separate group and have the name similar to `[sort]-[parent-slug]:[child-slug]` where sort refers to the sorting of the `child-slug` and not the parent. Also parent-slug does not need to have the sorting information as a part of slug e.g. if parent was `100-internet` the children would be `100-internet:how-does-the-internet-work`, `101-internet:what-is-http`, `102-internet:browsers`.

View File

@@ -14,6 +14,7 @@
"upgrade": "ncu -u",
"roadmap-links": "node bin/roadmap-links.cjs",
"roadmap-content": "node bin/roadmap-content.cjs",
"best-practice-content": "node bin/best-practice-content.cjs",
"test:e2e": "playwright test"
},
"dependencies": {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
# Minimize iframe count

View File

@@ -0,0 +1 @@
# Minify css

View File

@@ -0,0 +1 @@
# Make css files non blocking

View File

@@ -0,0 +1 @@
# Inline critical css

View File

@@ -0,0 +1 @@
# Avoid inline css

View File

@@ -0,0 +1 @@
# Analyse stylesheets complexity

View File

@@ -0,0 +1 @@
# Compress your images

View File

@@ -0,0 +1 @@
# Choose image format approprietly

View File

@@ -0,0 +1 @@
# Minify your javascript

View File

@@ -0,0 +1 @@
# Use non blocking javascript

View File

@@ -0,0 +1 @@
# Use https on your website

View File

@@ -0,0 +1 @@
# Page weight below 1500

View File

@@ -0,0 +1 @@
# Page load time below 3s

View File

@@ -0,0 +1 @@
# Keep ttfb less 1 3s

View File

@@ -0,0 +1 @@
# Minimize http requests

View File

@@ -0,0 +1 @@
# Use same protocol

View File

@@ -0,0 +1 @@
# Avoid 404 files

View File

@@ -0,0 +1 @@
# Use http cache headers

View File

@@ -0,0 +1 @@
# Enable compression

View File

@@ -0,0 +1 @@
# Minify html

View File

@@ -0,0 +1 @@
# Use cdn

View File

@@ -0,0 +1 @@
# Prefer vector images

View File

@@ -0,0 +1 @@
# Set width height images

View File

@@ -0,0 +1 @@
# Avoid base64 images

View File

@@ -0,0 +1 @@
# Load offscreen images lazily

View File

@@ -0,0 +1 @@
# Serve exact size images

View File

@@ -0,0 +1 @@
# Avoid multiple inline js snippets

View File

@@ -0,0 +1 @@
# Keep dependencies up to date

View File

@@ -0,0 +1 @@
# Analyze js for perf issues

View File

@@ -0,0 +1 @@
# Use service workers for caching

View File

@@ -0,0 +1 @@
# Cookie size less 4096 bytes

View File

@@ -0,0 +1 @@
# Keep cookie count below 20

View File

@@ -0,0 +1 @@
# Pre load urls where possible

View File

@@ -0,0 +1 @@
# Concatenate css single file

View File

@@ -0,0 +1 @@
# Remove unused css

View File

@@ -0,0 +1 @@
# Use woff2 font format

View File

@@ -0,0 +1 @@
# Use preconnect to load fonts

View File

@@ -0,0 +1 @@
# Keep web font under 300k

View File

@@ -0,0 +1 @@
# Prevent flash text

View File

@@ -0,0 +1 @@
# Check dependency size

View File

@@ -0,0 +1 @@
# Page speed insights

View File

@@ -0,0 +1 @@
# Lighthouse

View File

@@ -0,0 +1 @@
# Web page test

View File

@@ -0,0 +1 @@
# Chrome dev tools

View File

@@ -0,0 +1 @@
# Bundlephobia

View File

@@ -0,0 +1 @@
# Squoosh ap

View File

@@ -0,0 +1 @@
# Framework guides

View File

@@ -0,0 +1 @@
# Recommended guides

View File

@@ -0,0 +1 @@
#