-
Notifications
You must be signed in to change notification settings - Fork 2
6. Project Structure
Our project is built using the Feature-Sliced Design methodology, alongside the powerful capabilities of Next.js. This architectural approach allows us to organize our code in a way that is modular, scalable, and easy to maintain.
Feature-Sliced Design promotes the division of a system into layers and segments, which helps in effectively managing the complexity of the project. The key concepts include Layers:
- App: The core layer of the application, containing global settings, providers, configurations, and entry points. In our setup, the App also serves as the host for the prepared pages, ensuring seamless integration with Next.js routing and rendering.
- PreparedPages: Due to our use of Next.js, what would traditionally be the Pages layer in Feature-Sliced Design is referred to as PreparedPages. This layer contains the pre-configured pages that are ready to be rendered, encapsulating specific logic and UI for distinct user screens.
- Widgets: Components that combine several features or entities to create reusable UI blocks. These are more complex than simple UI elements and are used to build significant portions of the user interface.
- Features: reused implementations of entire product features, i.e. actions that bring business value to the user.
- Entities: This layer handles domain-specific entities, such as user models, product data, etc.
- Shared: Contains shared resources, utilities, and components that can be reused across different features and layers.
By following this structure, we ensure that our codebase remains clean and organized. Each layer is responsible for a specific part of the application, which makes it easier to manage and scale the project as it grows.
It is important to note that in accordance with the principles of Feature-Sliced Design, modules cannot directly use or depend on the same or higher-level modules. This ensures that the architecture remains modular and that each layer's responsibilities are clearly defined and maintained. For example, a module in the Entities layer should not directly import or depend on a module from the Features or App layers. This separation helps maintain the integrity of the architecture and supports the scalability of the project.
In our project, modules should use relative paths within themselves, but when referring to other modules, we make use of absolute paths through a central index.ts file. This allows for a clear structure internally while maintaining scalability and ease of navigation when interacting across different layers or features.
Within a module, all internal dependencies should be imported using relative paths to keep the module self-contained and flexible.
// features/MyFeature/ui/MyComponent
// Correct: relative import within the same module
import { MyComponentHeader} from '../MyComponentHeader/MyComponentHeader';When importing between different modules, we use absolute paths that are configured based on the index.ts file (Public API) of each module.
- Create an
index.tsfile in the module folder to centralize exports:
// features/MyFeature/index.ts
export { MyComponent } from './MyComponent';- Use absolute imports to access this module from another feature or layer:
// Importing MyComponent from another module
import { MyComponent } from '@/features/MyFeature';By organizing imports in this way, we achieve the balance between modularity and simplicity, ensuring that each module is both isolated and easy to reference from other parts of the codebase.


