My personal tips how to configure a SPFx project after creation

My personal tips how to configure a SPFx project after creation

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 of src.

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 the src path again. And because the file is in a folder, you need to add a '..' after __dirname when calling the path.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 :)

Did you find this article valuable?

Support $€®¥09@ by becoming a sponsor. Any amount is appreciated!