How To Bundle Angular HTML Template Files In SharePoint Framework (SPFx) Webparts


In this article we are going to see how to compile TypeScript files to JavaScript with the Angular 4 html template files by using a custom built toolchain. SharePoint Framework doesn’t provide a direct toolchain for Angular components but it will be announced in the near future.

SPFx build tool chain

The SharePoint Framework toolchain is the set of build tools, framework packages, and other items that manage building and deploying your client-side projects.

SPFx uses gulp as the build process runner and it enables us to integrate our custom gulp tasks to SPFx build pipeline. That’s the key for us to bundle the angular template files.

Normally gulp tasks are defined in gulpfile.js file. To view the available tasks in your SPFx project use the command

gulp  --tasks

The custom tasks that can be run out of the SPFx build pipeline scope can be added anywhere and you can run it independently like running other gulp tasks (Ex; gulp {CustomTaskName}).

If you want to add any custom tasks that must run along with SPFx build tool chain it should be defined before initializing the global gulp instance, before this piece of code: 


What happen if we don’t use custom gulp tasks to bundle angular templates in SPFx?

Normally in Angular we will be giving the template URL’s in the component files like below in Angular’ s Component decorator.


  1. @Component({  
  2.   selector: 'my-spfx-app',  
  3.   templateUrl: `app.component.html`  
  4. })  


Code Snippet: 1

SharePoint framework doesn’t recognize the base URL of this template file “app.component.html” while executing your app through gulp serve command and we will end up with file not found error in the console window.

But at the same time if you intentionally hard code the base URL like the below code snippet in the component itself, the execution will work perfectly.


  1. @Component({  
  2.   selector: 'my-spfx-app',  
  3.   templateUrl: `src/webparts/hfCommunity/app/components/app.component.html`  
  4. })  


Code Snippet: 2

And it’s not good practice to mention the base path of the html file in each component that you use in the project.

Otherwise, you have to use the template directly in the typescript file like below which is not suitable for the bigger projects.


  1. @Component({  
  2.   selector: 'my-spfx-app',  
  3.   template: `<h1>Welcome to SPFx {{name}}!!</h1>`  
  4. })  


Code Snippet: 3

So, the solution is we should convert the template html files into an inline html template code and inject it into the component after compiling the Typescript file into a JavaScript file through SPFx build toolchain.

Adding custom tasks in SPFx build tool chain to bundle angular html templates

There are some gulp tasks already available which we just need to incorporate into the SPFx build took chain, which will help us to append the compiled template html into component. Add the below packages in your package.json file like below,


  1. "gulp-inline-ng2-template""4.0.0",      
  2. "gulp-typescript""3.1.6",  


Code Snippet: 4

Now go to your npm command prompt and make sure that the terminal is pointing to your project directory and restore the newly added package dependencies by using the command npm install gulp-inline-ng2-template and npm install gulp-typescript


E:\your project directory >npm install

After the package installation go to your gulpfile and inherit the added packages in separate variables like below, in-addition to the package we will be using typescript configuration setup from tsconfig.json file which is already there in the project.


  1. var inlineNg2Template = require('gulp-inline-ng2-template');  
  2. var ts = require('gulp-typescript');  
  3. var tsProject = ts.createProject('./tsconfig.json');  

Code Snippet: 5

We have all the prerequisites ready, it’s time create the subtasks like below


  1. let hftsInlines = build.subTask('tsInlines'function(gulp, buildOptions, done) {  
  2.     return gulp.src('src/webparts/{webPartName}/app/**/*.ts')  
  3.         .pipe(inlineNg2Template({ base: '/src/webparts/{webPartName}/app/', useRelativePaths: true }))  
  4.         //above pipe is to convert the template URLs in to an inline template html code  
  5.         .pipe(tsProject())  
  6.         //aboce pipe is to compile the typescript code into a JavaScript code  
  7.         .pipe(gulp.dest('lib/webparts/{webPartName}/app'));  
  8.         //this last pipe is to place the converted JavaScript files in a destination location,  
  9.         //and our destination is lib folder because from there only SPFx takes reference to bundle the code into a single file  
  10. })  

Code Snippet: 6

Please find my comments in the above code snippet for more details about this subtask. Make sure you have replaced the highlighted content with your webpart name.

Now that we have created the subtask tsInlines in SPFx build pipeline, the executing order of this subtask matters so we should register this subtask after the SPFx default typescript tasks are completed.

Why do we need to run this subtask after SPFx Typescript task?

If we run our subtask before SPFx typescript task, the converted JavaScript files in the lib will be overwritten by the output of the actual SPFx typescript task and we will end up with the same issue again.

But if we execute it after the SPFx typescript task, the final output in the lib folder will be from our subtask only, so we are good to go now.

Below is the code snippet to register the subtask after the SPFx typescript task


  1. build.rig.addPostTypescriptTask(hftsInlines);  


Code Snippet: 7

The above code snippet must be added before initializing the global gulp instance, that is, before this piece of code 


Please refer to the SPFx official documentation to learn more about integrating gulp tasks in SPFx build pipeline.


In this article, we have discussed overview of SPFx build toolchain and how to compile and bundle the html component files in Angular 4 integrated with SPFx and why we need to do that with a detailed explanation.

If you have any questions/issues about this article, please let me know in the comments.