Showing posts with label NPM. Show all posts
Showing posts with label NPM. Show all posts

Monday, 29 April 2019

Using Microsoft Rush to manage SPFx projects with library components

If you haven't heard about Rush JS yet, you are probably not alone. In my opinion it's one of the hidden gems of the SPFx ecosystem or even the larger web dev ecosystem for that matter. It's a great open source tool which can be used to manage large repositories (monorepos) containing multiple node/npm projects with dependencies on each other. To know more about Rush, you can visit its website: https://rushjs.io/

In this post, we are specifically going to look at how we can use Rush to manage SPFx repositories containing multiple solutions including SPFx library components, web parts and extensions.

With SPFx library components being introduced in preview in v1.8 and expected to be generally available in v1.9, sooner or later you might find yourself trying to manage large SPFx repositories like this:
(click to zoom)

In this repo, there are 4 SPFx solutions: The org-app solution contains SPFx components which depend on org-library which is an SPFx library component. org-library itself depends on another SPFx library component util-library. And finally, another "consumer" solution org-app2 depends directly on util-library

When working in this type of repository, things will get tricky to manage real fast because of the various SPFx solutions, their dependencies on each other, needing to run gulp build or gulp serve multiple times after changing a single file, remembering which consumer projects to update after the libraries have been changed, managing multiple node_modules folders (if not using pnpm) etc. This is where Rush comes in.

If all projects are part of one Rush repository:
  1. You don't have to manage node_modules folders individually for each project. Rush will maintain a common node_modules folder and create symlinks in each project which point to it.
  2. Rush will also create a single lock file for your entire repository and all projects.
  3. You don't have to use npm link to connect your library to consuming webpart packages. Rush handles all the linking and unlinking for you.
  4. When you are working on the library and the consumer components simultaneously, you don't have to run gulp build multiple times. You just need to run "rush build" once. More on this later.
  5. When working on multiple libraries and components with different dependencies, you don't have to keep track of which webpart depends on which library. Rush will do this for you and handle the necessary updates.
  6. Based on your project dependencies, Rush will parallelise builds of projects which do not depend on each other. Thus, reducing build time.
Now before you go converting all your existing repositories to Rush, there are a couple of considerations to think about as well:
  1. Most Rush commands only work with Git repositories. It uses git change tracking to determine which files changed and which repositories to update. So, if you are using TFVC or any other version control system, you might be out of luck. More details on this here: https://github.com/Microsoft/web-build-tools/issues/1250
  2. When working on SharePoint Framework projects in a Rush repository, the local workbench seems to be broken currently. The SPO workbench works. A bug is logged here: https://github.com/SharePoint/sp-dev-docs/issues/3736
Now with all that out of the way, lets create a simple Rush repository with just couple of SPFx components! What we are going to do is create a Rush repository, create an SPFx library component (corporate-library), then create an SPFx webpart component (corporate-apps) and then consume the library component from the webpart. We will then use Rush to build and manage this repository.



First, we need to perform some setup:


This should install rush, convert your root folder to a git repo and a rush repo, and then commit the rush files to git.

Next, we will create the SPFx library component:


Notice we are using the --skip-install flag as we don't want to install the npm packages right now. We will do this with rush later. Select the options as in the following image:


Add the SPFx library component to your git repo:


Next, we will create the SPFx webpart project:


We will again use the --skip-install flag to skip installing the npm packages.

Select the options as per the following image:


Now add the webpart project to your git repo:

Your final solution structure should look like this:


Next, we need to tell Rush that the corporate-apps project has a dependency on the corporate-library project. We will do that by updating the dependencies in the corporate-apps/package.json file


After this, we need to configure Rush to work with our repository and project structure. For this, we need to update the rush.json file in the root folder. 

We can define the node, npm and rush versions we will use for this repository. You can use other package managers like pnpm and yarn with rush as well. For a list of all available options see here: https://rushjs.io/pages/configs/rush_json/

More importantly, we need to define our project folders and package names in this file. This is what Rush uses to find folders corresponding to package names.

By default, the file has a lot of config options and comments, but we only need these values for the demo:


Next, as we are going to use npm as the package manager, we need to delete the common\config\rush\pnpmfile.js file as it is only meant to be used with pnpm.

After this, it is time to install all the npm packages needed by all the projects in our repository. For that we just need to run:




Rush will install all npm packages in the common\temp\node_modules folder and create symlinks in each project to the common folder.

Next, we need to build our repository with:




Due to the dependencies added the corporate-apps/package.json file, Rush will build the library project first and then the consumer project.

Now we can use the code from our library project in our webpart project. Go to the corporate-apps\src\webparts\consumer\ConsumerWebPart.ts and add the following code:

If you run rush build again, you will see that the library project is not updated. This is because rush knows that only the webpart files changed and it should only update the relevant projects. Here is a working demo of the repository:

(click to zoom)

And that's it! You can now build on this to start including multiple SPFx libraries and components to your repository.

Here is an image of a larger Rush repository in action (the same one mentioned at the start of this blog) You can see that depending on the files changes, Rush updates only the required projects.


Also, all your projects in the Rush repository are still standalone SPFx projects. You can navigate to each project's working directory and run gulp build, gulp bundle or gulp package-solution just like you would in normal SPFx projects.

Hope you find this post helpful! Let me know in comments if you feel there is anything I have missed.

Links:

1) The simple Rush repository we built in this post: https://github.com/vman/SPFxRushSimpleDemo
2) Slightly more complex Rush repository: https://github.com/vman/SPFxRushComplexDemo
3) SPFx library component overview: https://docs.microsoft.com/en-us/sharepoint/dev/spfx/library-component-overview
4) Rush website: https://rushjs.io/

Thursday, 27 July 2017

Simultaneously run multiple versions of the SPFx Yeoman generator with npx

This is a topic which has been discussed quite a lot since the launch of the SharePoint Framework. The SPFx Yeoman generator is recommended to be installed globally, but what if a new version is released and I want to try out the new version without uninstalling my globally installed generator? 

Waldek Mastykarz has a great post on the issue and suggests some solutions as well. Have a look at his post if you haven't already: Why you should consider installing the SharePoint Framework Yeoman generator locally

In this post, lets have a look at how we can use npx to provide a solution to this problem.

If you haven't heard about npx yet, it is the hot new member of the node ecosystem. Check out the introduction post by Kat Marchán:

In short, npx can be used to run npm packages directly from the command line without having to install them globally or locally.

From the intro post:

Calling npx <command> when <command> isn’t already in your $PATH will automatically install a package with that name from the npm registry for you, and invoke it. When it’s done, the installed package won’t be anywhere in your globals, so you won’t have to worry about pollution in the long-term.

This means that when we run the SharePoint Framework generator through npx, it will be as if it is running from a global install. After the SPFx solution is created, you will not find the generator installed either locally or globally. It has served it's purpose of generating us a solution and is no longer needed. 


Run different versions of the SPFx Yeoman generator in different folders: 


Now lets actually use npx to create two different SPFx solutions using two different versions of the SharePoint Framework Yeoman generator. We will use the latest version of the generator and the very first version of the generator which was part of SPFx Drop 1.

I am using the following command throughout the post to list the top level global packages:



I have done a global install for gulp already. This is to keep things simple as we only want to use npx for the SharePoint Framework generator. If we wanted to take things to the next level, we could use gulp through npx as well.

Now, let's go ahead and install npx globally:


After it's installed successfully, lets have a look at our global packages again:


As you can see, neither the SharePoint Framework generator, nor Yeoman itself is installed globally. This makes us free to use any version of the generator we want. Let's use the latest version, which at the time of this writing is 1.1.0

First, I am going to create a new folder named "latest" and navigate to it. Then run the following:


By specifying the -p (package) flag we run the yeoman (yo) and SPFx generator (@microsoft/generator-sharepoint) packages through npx. 

After that, we run the SharePoint Framework generator by running  -- yo @microsoft/sharepoint

 



Now let's run gulp serve to launch the workbench. As mentioned before, since we have already installed gulp globally, we don't have to install it again.




Now let's see the real power of npx. We will navigate to another folder and use Drop1 of the SharePoint Framework generator to create an SPFx solution.

I have created another folder called drop1. Lets navigate to it and run the following using npx:


As you have probably noticed already, the only difference in this and the previous npx command is that we are using the version numbered 0.0.65 of the generator and not the latest. This was the version of the generator when Drop 1 of the SharePoint Framework landed back in August 2016.


You will notice immediately that there are some differences in the wizard. It asks me whether to create a new folder for the solution or use the current folder. It also defaults to creating a web part and does not ask me whether I want to create an extension. This is obvious given that extensions were not part of the first drop. 

After running gulp serve, we can see the Drop 1 workbench running:



That's it! We have used two different versions of the generator to create two different solutions without having to install the generator on our machine!

Using a new version of the SPFx generator when an older version is already installed globally:


If you have been closely following the post, you know what's coming next. 

Let's say we already have a version of the generator installed globally. Now a newer version of the SPFx generator is released and we want to try it out immediately. All we have to do is use npx to run the latest version. We would be able to create a new SPFx solution with the latest generator and still keep our old generator installed globally!

The magic is described in the npx package description

If a full specifier is included, or if --package is used, npx will always use a freshly-installed, temporary version of the package. This can also be forced with the --ignore-existing flag.

This is good news because we want to have control over which generator version is used by npx to create our solution.

Here is how the process will look:


I already have the Drop 1 (0.0.65) version of the generator installed globally. Next, we are running npx and specifying it to use the latest version of the generator.

After the command is run, we are presented with the wizard which gives us the option of creation an SPFx extension. This option was not available with Drop 1 which means that the latest generator is being used to create our solution.

This is how we can use npx to explicitly specify the generator version and ignore the globally installed generator!

Where does npx store the packages?


If we navigate to our npm-cache folder, we will see that npx stores all the versions of the package in the cache. Here, we see that the @microsoft/sp-build-web package was used in both versions of the generator, hence both versions are being stored in the cache:


That's it! Hope you have enjoyed this post as much as I have enjoyed writing it :)

Tuesday, 13 September 2016

SharePoint Framework: Org Chart web part using Office UI Fabric, React, OData batching and Service scopes

Here is a SharePoint Framework web part I have put together to show an organisation chart for the current user: 

Code is available on GitHub as part of the SharePoint Framework client-side web part samples & tutorials: https://github.com/SharePoint/sp-dev-fx-webparts/tree/master/samples/react-organisationchart


(click to zoom)

1) For getting the Manager and the Reports of the current user, the ExtendedManagers and DirectReports user profile properties are used.


2) Uses the OrgChart CSS directly from the Office UI Fabric: http://dev.office.com/fabric/OrgChart (Not the Office UI Fabric React components which are still in progress)


The Office UI Fabric CSS is bundled together with the web part and not referenced externally. In the OrganisationChart.module.scss:

Thanks to my colleague and buddy Paul Ryan for this tip.

3) The REST API calls are made with the HttpClient belonging to the current ServiceScope. No need to pass web part properties or the web part context. 



4) The Managers and DirectReports are fetched by registering a mapping of the UserProfileService class in the current ServiceScope



5) OData Batching is used to get details (Photos, Titles, Profile Urls) of all DirectReports in a single call. (Similarly, if more than one Manager exists in the ExtentedManagers property, details of all users are fetched in a single batch call)


More on OData Batching in my previous post: Batch REST requests in SPFx using the ODataBatch preview

Hope you find this useful!

Monday, 18 July 2016

Getting started with TypeScript, Browserify and Gulp in SharePoint

In my previous post Simple bundle, minify and upload JS to SharePoint using Gulp we saw how Gulp tasks can be used to simplify our JavaScript development experience in SharePoint. I am really impressed with Gulp as it has increased my productivity and I don't remember the last time I used SharePoint Designer :)

Now let's see how can we bring TypeScript into the mix. I have been playing around with TypeScript for a while now and here is my basic development workflow:

1) Create a main app.ts file which will contain the primary code for my application or "WebPart". In addition, app.ts will also have import references to any custom or third party modules e.g. jQuery

3) Use tslint to check the quality of my TypeScript

4) Use browserify and tsify to parse my TypeScript file and create a single JavaScript file (app.js) which includes all the dependencies required to run my app.

5) Minify my app.js using gulp-uglify and rename it to app.min.js using gulp-rename

6) Upload the debug and minified files to the Style Library in SharePoint using gulp-spsave

7) Then the JavaScript files can be used any way I like e.g. embed it using a Custom Action or in a Script Editor or a Content Editor WebPart.

Before we begin, if you are using Visual Studio 2015 like me, make sure you have the latest version of Node installed and Visual Studio is configured to use it. Here is an excellent tutorial on how to do this: How to configure Visual Studio 2015 with the latest version of Node.js and NPM

Now let us have a look at the important bits of my solution. I have uploaded the entire solution on GitHub here: https://github.com/vman/MyTypeScript

1) app.ts file:


At the top, the import statements are used to indicate that the code in this file is dependent on these modules. The first being jQuery and the second being my custom User module. Next, we simply create an object of the User class and call it's getDetails and displayDetails methods.

2) User.ts


There is a bit more going on in my User.ts class. Just like my app.ts, the first line indicates, with an import statement, that this file is dependent on the jQuery module. The getDetails function gets the AccountName, DisplayName and Email of the current user from the SharePoint REST API and stores them as properties of the current instance. The  displayDetails function logs the same properties (of the current instance) to the console.

3) package.json


Here is a list of all npm packages used in my solution. Notice the jQuery package, browserify and tsify use it to include jQuery in the final bundle as it is requested by my app.


4) gulpfile.js


And finally, here is my gulpfile.js which does all the heavy lifting:


5) Gulp tasks:


The watch-ts-upload-to-sp task looks for any changes in the .ts files (app.ts and User.ts). If any changes are noticed, it runs the upload-to-sp task.

The upload-to-sp task has dependencies chained up so that the tasks are run in the following order:

1) lint-ts to check the code quality of TypeScript
2) browserify to import all the required modules and create a single app.js bundle file
3) minify-js to create a minified file.
4) Finally, the upload-to-sp task runs to upload the app.js and app.min.js files to the Style Library.

(click to zoom)


A note on Typings:


TypeScript uses TypeScript definition '.d.ts' files to provide intellisense while writing a file. The TypeScript Definition Manager "Typings" is the current recommended approach of including definition files in your project: https://github.com/typings/typings

I have included typings as an NPM package in my solution (have a look my package.json file) and then used the following commands to get the required typings in my project:

Thanks for reading!