This is an example of a re-useable hybrid-repo, SharePoint (SPFx) MVC implementation. It uses git-modules, yarn workspaces, PnPjs, SPFx-Controls, MobX and Fluent UI. The goal is to provide a starting point for rapid SPFx development. Using this platform, I was able in 2 hours to develop a minimal extension using a normal lifecycle:
- start in a development environment from an example solution
- test and fix something
- adjust generic documentation
- deploy to production environment
The example workspaces share the same SharePoint Controller, SPFx views and several tool packages. It hopefully illustrates:
- git modules to organize reusable extendable projects (hybrid repro)
- reusable modules for the basics, data source access and presentation
- create a model for your specific SharePoint lists
- focus on business logic development
- an extendable framework by your contribution
- Summary
- Table of contents
- Getting Started
- Overview
- Example solutions
- Real world example
- How to use it
- Contribute
Go to any repository of the example solution in the solutions folder and follow the README.md
. Basically clone
and serve
.
This is only useful for looking around and comparing the projects. It's easier for build and enhancements to clone each example solution.
git clone --recurse-submodules https://github.com/mauriora/reusable-hybrid-repo-mvc-spfx-examples.git
To jump start a new SPFx project, use any of the examples in the solutions folder as a starting point:
- Fork the example workspace as YOUR-SOLUTION
- Clone the forked workspace
- Fork the starting app project as YOUR-PROJECT
- Add YOUR-PROJECT as submodule to YOUR-SOLUTION
- the app GitExtension can be helpful
- under
Repository
/Manage submodules...
- Remove the starting project, and any other you don't need, from YOUR-SOLUTION (see previous step)
- call
yarn initguids
in apps/YOUR-PROJECT - rename YOUR-..... in:
- app/YOUR-PROJECT
- package.json
- src/webparts/YOUR-WEBPART
- YOUR-WEBPART.manifest.json
- config
- config.json
- package-solution.json
- app/YOUR-PROJECT
The goal of this project is to provide a starting point, to rapidly develop components while re-using and enhancing shared libraries.
The README.md
in the submodules document the specific component, like Controller. This document focuses on the shared architecture and shared processes.
Each workspace appears like a mono-repo on the local hard drive, yet it's created from independent repositories.
Using yarn workspace mostly one node_modules
folder is shared between all projects within a workspace.
You can enhance a shared module and use/test it immediately in your app without publishing it.
Each of the workspaces uses (some) shared modules.
The MVController implementation and (currently) contains the base classes of the ModelVC).
The M-View-C providing wrappers and tools for @pnp/SPFX-Controls-react and @FluentUI/react. Mostly being HOCs providing an uniform interface to work with the MVController.
MobX is used for state management and data-driven events. Instead of creating and registering specific events, the observer pattern is used.
Each of the solutions illustrate a different SPFx category. All create their own list model extended from a built in one.
Published | Name | Category | Illustrated topics |
---|---|---|---|
[x] | Announcements bar | Extension | separate deployment packages for extension and lists |
[x] | Keyword-Feedback | Extension, Web part | 2 deliverables from 1 solution |
[x] | WebPart-Test | Web part | all field controls on a form, graph API registration |
This is a simple real world example of a store extending PNP Search and using this architecture. The Store is implemented by an Agency for a Client.
In the apps folder are the deliverables:
- Navigation, as a search filter
- Search Item View, a search extension component implementing a dynamic property
AddToCart
defined inStore Dynamic Data
- Cart uses
Store Dynamic Data
to connect to aAddToCart
dynamic data source - Manager uses the same
Store Models
as used by theCart
In the shared folder are the modules used by the apps:
- SPFx Controls contains view elements optimized to work with the
SharePoint Controller
- SharePoint Controller implements access to SharePoint and defines the Base classes for Models
- Store Models contains extensions of the SharePoint base models for the list required for the store
- Agency Utils frequently used code snippets used by most deliverables
- Store Dynamic Data defines the interface for the DynamicData source
Each color represents a repository location:
- blue are the repositories owned by the client, containing the specific business logic and domain models
- green open source modules used
- orange the agencies own utils library
This explains how to use the different aspects of the MVC implementation and hybrid-repos.
- Create the workspace (fork & clone a solution) with all required modules
- Create models for your specific lists
- Implement your business logic
- Test with serve
- Build package and deploy
Depending on the stage or kind of your development, you may not want to download and build all submodules.
You can unloadModules
which are published.
You could also Install the workspace by cloning the solution and loading only the modules you need:
git clone https://github.com/mauriora/Announcements-Bar-Spfx.git
cd Announcements-Bar-Spfx
yarn install
yarn loadModules .\app\Announcements-Bar-Extension\ .\app\Announcements-Lists-Deployment\
yarn build
When updating code in a shared module, run yarn build
in the module and the changes are available in the workspace.
Usually you would have an app running using serve
, go to any of the app files and save it (without modifying), this
will cause webpack to reload your changes in a shared module.
After working across the different models, run in the root folder:
yarn run version
This will:
- open an interactive prompt to choose the new version for each modified module
- apply the new versions to the modules and update the version in their references (
dependencies
in otherpackage.json
) - call
run version
in each workspace, the SPFx modules callsyncVersion
to update thepackage-solution.json
,<ExtensionName>.manifest.json
, ... with the new version frompackage.json
Models usually live in a shared module, as you may use the same model in different workspaces and solutions.
A model usually extends from ListItem
. They map Datasource columns to properties. Please refer to Controller-SharePoint-List for more details.
export class Announcement extends ListItem {
@Expose({ name: 'Body'})
public body?: string;
@Expose({ name: 'Expires'})
public expires?: string;
}
Any contribution is valued and helps.
Please submit your pull request to the corresponding repositories development branch.
- Architecture overview
- Create new project scaffolding process
- Replace lerna with
- yarn 2
- Automatic publish
- sub modules npm packages
- NPM
- Azure
- .sppkg deployment
- sub modules npm packages
- Styling (js based)
- Examples
- List Extensions
- Teams
- Library
- Controller
- Single Column Taxonomy fix through TaxCatchAll field
- Utils modules
- Config module (e.g. default tsconfig, eslintrc, ...)
- Theming/branding module per client