It is very easy to create a new SPFx project and you can find a lot of posts about it. One of these posts is, of course, the one from Microsoft. But what should you do after the "empty" project is created?
I will describe what I personally do after I create a new project. Some steps may not be relevant for you because you prefer a different way of working or structure your project differently. But maybe there's one or two things you didn't know yet and think it's good.
NOTE: In the meantime, I have developed a CLI that automates the settings mentioned here and more for you. Read more
SPFx fast serve
I have often mentioned that I like the npm package spfx-fast-serve developed by Sergei Sergeev. If you don't know it, you must use it! So the first step I do after creating the project is to run the spfx-fast-serve
command in my terminal. This is of course only possible if you have installed the package globally before. After running the command, the tool prompts you to run the npm install
command again. Since I switched to pnpm, of course, I have to run pnpm install
Configure (path) Alias
Most use relative paths to refer to files from the solution. Here are a few examples:
import HelloWorldWebPartComponent from './components/HelloWorldWebPartComponent';
import { MyComponent } from '../../components/MyComponent';
Custom aliases allow you to create (mostly) shorter and more intuitive paths for your imports. This is especially beneficial in larger projects where multiple levels of folder structures can lead to unwieldy (relative) paths. But it is also helpful if you want to reuse the modules later because then you don't have to work with the relative paths anymore. Here is the same example as above, but with the alias:
import HelloWorldWebPartComponent from ' @webparts/helloworld/components/HelloWorldWebPartComponent';
import { MyComponent } from '@components/MyComponent';
Extending tsconfig.json with baseUrl and custom Alias
The tsconfig.json
file is the configuration file for TypeScript projects and provides various options to control the behavior of the TypeScript compiler. By extending this file in your SPFx solution, you can better customize the TypeScript compilation process to suit your project structure and needs.
1. Adding baseUrl
The baseUrl
property in tsconfig.json
allows you to set a base directory for module resolution. This means you can define a central starting point for your imports, reducing the need for long relative paths.
For example, by including a baseUrl
property pointing to your project's src
directory, you establish a foundation for cleaner, more intuitive imports. But I personally point to '.'
. Here is an example of how the file tsconfig.json
looks like after the change:
"compilerOptions": {
"baseUrl": ".",
// Other options...
}
2. Defining Aliases
To create a custom alias, add the paths
property under compilerOptions
in your tsconfig.json
. This property maps aliases to their corresponding paths.
I always create an alias for the src
folder (that's why my baseUrl
points to '.'
and not 'src'
), the webparts
folder and the components
folder. But of course, you can also create your own alias. This is how the tsconfig.json
looks like after the change:
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.5/includes/tsconfig-web.json",
"compilerOptions": {
// Other options...
"paths": {
"@src/*": ["src/*"],
"@components/*": ["src/components/*"],
"@webparts/*": ["src/webparts/*"]
},
"baseUrl": "."
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
]
}
Registering custom aliases in Gulp
After defining aliases in your tsconfig.json
, you must ensure they work during the build process. This involves syncing the aliases with the build output.
In your gulpfile.js
, before the build.initialize(require('gulp'));
code part, add this:
build.configureWebpack.mergeConfig({
additionalConfiguration: (generatedConfiguration: any) => {
if (!generatedConfiguration.resolve.alias) {
generatedConfiguration.resolve.alias = {};
}
// webparts folder
generatedConfiguration.resolve.alias['@webparts'] = path.resolve(
__dirname,
'lib/webparts'
);
// components folder
generatedConfiguration.resolve.alias['@components'] = path.resolve(
__dirname,
'lib/components'
);
//root src folder
generatedConfiguration.resolve.alias['@src'] = path.resolve(
__dirname,
'lib'
);
return generatedConfiguration;
}
});
Make sure that you have added the path
package to the beginning of your gulpfile.js
const path = require('path');
NOTE: In gulpfile, you should use the
lib
folder instead ofsrc
.
Registering custom aliases in spfx-fast-serve
After running the command spfx-fast-serve
in your terminal (described above), the command added a new folder in the root of your project, called fast-serve
, containing a file called webpack.extend.js
. Again, we need to register the alias so webpack
can resolve it.
There should be an (empty) variable webpackConfig
in the file:
const webpackConfig = {
}
Now you have to extend this and register your alias:
const path = require('path');
const webpackConfig = {
/* CUSTOM ALIAS START */
resolve: {
alias: {
"@webparts": path.resolve(__dirname, "..", "src/webparts"),
"@components": path.resolve(__dirname, "..", "src/components"),
"@src": path.resolve(__dirname, "..", "src"),
}
},
/* CUSTOM ALIAS END */
}
NOTE: In
webpack.extend.js
you should use thesrc
path again. And because the file is in a folder, you need to add a'..'
after__dirname
when calling thepath.resolve
method. And again, do not forget to import the path package!
That's it, now you can use your defined alias instead of relative paths!
Create Gulp task to increase the (package) version
If you want to have a command to increment the SPFx solution version (config/package-solution.json
) and the package.json
version, then you should define a custom gulp task like I do. And even more, if you want to build the solution, increase the version and package the solution with one command, then you should read my post on how to do that.
Optional steps
I know the following steps aren't relevant to everyone or may not even appeal, but these are the ones I always do!
Disable CSS class name warnings
I often use CSS class names that do not conform to the Microsoft schema and are not camlCase. An example would be spfxappdev-grid
.
When I define this, I get a warning
Warning - [sass] The local CSS class 'spfxappdev-grid' is not camelCase and will not be type-safe.
To remove this warning, you can suppress it in gulpfile.js
. An SPFx project even suppresses such a warning for Microsoft's own CSS class by default. You can find it in the gulpfile.js
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
Of course, I could now add a new suppression by entering the following
build.addSuppression(`Warning - [sass] The local CSS class 'spfxappdev-grid' is not camelCase and will not be type-safe.`);
But I won't. Because I have more than just this one class. To suppress all these messages you can use RegEx:
build.addSuppression(/Warning - \[sass\] The local CSS class/gi);
That's it!
Change ESLint Rules / TypeScript rules
Since SPFx v.1.15 was released, Microsoft switched from TSLint to ESLint. Actually a good decision, but some rules annoy me personally. Especially if you use spfx-fast-serve
and you are still developing the modules. Sometimes you just want to test something fast and define variables that are not used (yet). Or you comment out a code and the method is now "empty". Then errors are output and often the spfx-fast-serve
process is stopped => you have to start it again after fixing.
For this reason, I change the rules before starting development. To change them, open your .eslintrc.js
and set your own values. For example, I change these rules to 0
(0
= '0ff', 1
= 'warning', 2
= 'error'):
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-floating-promises': 0,
'@typescript-eslint/no-unused-vars': [
0,
{
vars: 'all',
// Unused function arguments often indicate a mistake in JavaScript code. However in TypeScript code,
// the compiler catches most of those mistakes, and unused arguments are fairly common for type signatures
// that are overriding a base class method or implementing an interface.
args: 'none',
},
]
And then I also change the tsconfig.json
. I add these compilerOptions
:
"compilerOptions": {
// Other options...
"noImplicitAny": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
}
By the way, here is a good article if you want to learn more about ESLint with SPFx.
I don't have to do this every time, thanks to my CLI
Since I have done these above steps every time, for every project, I wanted to simplify it a bit. So I developed my own command line interface (CLI) that does just that (Read more about my CLI).
This is my typical folder structure
It has less to do with the topic of the article, but maybe someone is interested in what my folder structure looks like, which I (almost always) create. Of course not immediately, but only when I need it.
src
|- models
|- interfaces
|- services
|- components
|- webparts
|- components
|- ...
The components
folder directly in the src
folder is only for components I use in further SPFx modules (e.g. if I have more than one webpart or extension).
That's it
I hope you enjoyed the article and got some helpful tips. I would also be happy about feedback. Gladly also with your tips :)
Happy coding :)