Frontend Development Best Practices and Common Pitfalls
This article presents a comprehensive guide to frontend development best practices, covering commit message standards, dependency management, import ordering, naming conventions, lint configuration, CSS property ordering, inline styles, code duplication, magic numbers, pure functions, and component structuring, with concrete examples and recommendations for improving code quality and maintainability.
Standardization Issues
Meaningless commit messages
It is recommended that everyone understand commit message conventions and configure commit lint for projects to experience the benefits.
Unused and default dependencies
Use depcheck to detect unnecessary dependencies.
Unused dependencies
* @alife/bc-big-brother
* @alife/scc-gangesweb-inquiry
* babel-runtime
* caniuse-lite
Unused devDependencies
* @ali/kyle-config-saga
* style-loader
Missing dependencies
* @src/utils: ./src/utils/do-dot.js
* @alife/bc-safe-log: ./src/utils/log.js
* @src/pages: ./src/pages/template/showroom-list/index.jsx
* @src/modules: ./src/pages/template/showroom-gallery/index-v2.jsx
* @src/components: ./src/pages/template/promotion-venue/index.jsx
* @alife/bc-video-player: ./src/pages/template/pla-detail/product-detail.jsxMixing dependencies and devDependencies
Because tnpm flattens dependencies, mixing them works but is considered amateur; consider using peerDependencies for true runtime dependencies.
Import order
In frontend code, imports generally fall into three categories: CSS, project files, and third‑party packages. Although no strict order is mandated, separating them improves readability and can be automated with tools like ESLint and Prettier.
Even the order of fields in package.json can be automatically sorted using sort-package-json .
Method names should be verb phrases
Instead of productListFetch() , prefer fetchProductList for clearer intent.
Leftover console debugging code
Configure ESLint to treat console statements as errors; use eslint-disable only when absolutely necessary.
Improper eslint‑disable scope
Avoid disabling ESLint for an entire file; disable only the specific rule on the line that needs it.
// eslint-disable-next-line no-alert
alert('foo');Refer to the official documentation for disabling rules: https://eslint.org/docs/latest/user-guide/configuring/rules#disabling-rules
Large commented code blocks
Instead of keeping dead code, rely on Git history and add a TODO marker if removal is postponed.
Misleading file extensions
If a file is named with .ts but contains no TypeScript, rename it to avoid confusion.
CSS property order
Common conventions group properties as layout/position, size, text, and others. Tools like prettier-plugin-style-order can enforce this automatically.
CSS class naming
Use lowercase letters; CSS is case‑insensitive.
Separate words with hyphens (e.g., block-element-modifier ) following BEM conventions.
Avoid single‑word class names to reduce naming collisions.
In CSS Modules, camelCase naming is recommended: https://github.com/css-modules/css-modules#naming
Static inline styles
function Demo() {
return (
{list.map(product => (
))}
);
}Inline static styles have two drawbacks: they lack semantic meaning and increase DOM size, affecting download time in SSR scenarios.
Repeated style overrides
Prefer precise scoping over layered overrides.
.container {
margin: 0 auto;
color: #333;
&.mobile {
color: #444;
}
}Can be refactored to:
.container {
margin: 0 auto;
&.pc {
color: #333;
}
&.mobile {
color: #444;
}
}Frontend Engineering Issues
Code not merged to master; use GitLab tags for identification.
Version numbers pushed outside the release process cause ordering problems.
Lint not effective; ensure proper configuration and Husky pre‑commit hooks.
README Without Value
A good README should include project description, environment setup, API documentation, and build/release commands, tailored to the project's type.
Common Method Misuse
Mixing forEach and map
Use map only when you need a new array; otherwise prefer forEach .
Array.prototype.map() creates a new array by applying a function to each element of the original array.
arr.map(item => {
item.name += '--';
});Optional chaining without compatibility check
Optional chaining simplifies null checks but may break in environments that do not support it.
const children = testObj?.elements?.items;
return (
<>{
children.map(item =>
{item}
)
}
);Unnecessary callback wrapping
getList()
.then(list => {
console.log(list);
});Can be simplified to:
getList().then(console.log);Await causing unnecessary serial calls
When calls are independent, run them in parallel with Promise.all .
const user = await getUser(userId);
const favorites = await getFavaritesByUserId(userId);
setStore(user, favorites);Better:
Promise.all([getUser(userId), getFavaritesByUserId(userId)]).then(setStore);Bad Programming Habits
Programming based on symptoms
if (indexOf('test') >= 0) {}
// special handling for top 3 ranks
if (index < 4) {}
if (ieVersion >= 9) {
// use Array.isArray
}Rewrite for clarity:
if (indexOf('test') != -1) {}
if (index <= 3) {}
if (typeof Array.isArray === 'function') {}Exhaustive conditional code
Example of version comparison using nested if statements; a loop simplifies the logic.
function compareVersion(v1, v2) {
const ver1Arr = v1.split('.').map(Number);
const ver2Arr = v2.split('.').map(Number);
for (let i = 0; i < 3; i++) {
if (ver1Arr[i] > ver2Arr[i]) return 1;
else if (ver1Arr[i] < ver2Arr[i]) return -1;
}
return 0;
}Magic numbers and constant extraction
if (column > 7) {}Extract such values into a constants module:
// constants.js
export const MAX_COLUMN = 7;Functions with side effects
({ activeIndex1, floorArray }) => {
let finalLiveList;
if (activeIndex1 === 0) {
floorArray[0].list[0].cardType = floorArray?.[0]?.cardType;
finalLiveList = [...floorArray[0].list, ...floorArray[1].list];
} else {
finalLiveList = [...floorArray[0].list];
}
return (
);
};Pure functions should avoid mutating input parameters.
Mixing thought process with implementation in render
Separate UI logic from component implementation for readability.
function Component1() {}
function Component2() {}
function Component3() {}
function Component4() {}
function Demo() {
return (
);
}Violating DRY principle
Avoid copying and modifying code blocks; refactor shared logic into reusable functions.
Cultivating Good Programming Habits
Writing robust, readable code reflects professional integrity; engineers should treat each line as a representation of themselves.
Technical literacy is the everyday cultivation of good coding habits.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.