I'm new to JS-based Office addins and I'm trying to create a sample Word addin with Angular 6 + Typescript.
To this end, I found the office toolbox which looks like a perfect start: https://www.npmjs.com/package/office-toolbox. Yet, its templates date back to Angular 1.x. So, I tried to experiment by merging an Angular 6 CLI new project with the template from the toolbox, without luck.
I tried two approaches. Of course, both require to first install the office toolbox globally:
npm install -g office-toolbox
Once the add-in is started, my understanding is that we must first copy the XML manifest and open it in Word, i.e.:
- copy the XML manifest from your project into a share you created for this purpose (e.g.
C:\Sideloads
); - start the addin (
npm start
orng serve
); - open a new Word document;
- open the
Developer
ribbon and clickAdd-ins
; - goto
Shared folder
, select your addin, and clickAdd
. A new button appears in the ribbon: click it to show its pane.
The problem is that an up-to-date solution for using Angular 6 with Office Addins does not seem to be present, and understanding the bootstrap process in this environment is not so trivial. So I tried with 2 hackish approaches, but none worked. Could anyone suggest a better way? Here are the approaches:
Approach 1
This follows the directions from the office toolbox site.
run
office-toolbox generate
and answer the questions to generate a new application with its manifest, based on Angular.now I'd like to try upgrading the project. I tried to change
package.json
by merging it with the default package fromng new
, and then runnpm install
. The package generated by the toolbox looks like this:
{ "name": "sample-add-in", "description": "", "author": "", "version": "0.1.0", "scripts": { "tsc": "tsc -p tsconfig.json -w", "server": "browser-sync start --config bsconfig.json", "copy": "cpx \"src/**/!(*.ts)\" dist --watch", "start": "rimraf dist && concurrently \"npm run tsc\" \"npm run copy\" \"npm run server\"", "validate": "./node_modules/.bin/validate-office-addin" }, "dependencies": { "core-js": "^2.4.1", "office-ui-fabric-js": "^1.3.0", "jquery": "^3.1.1", "angular": "^1.6.1", "office-addin-validator": "^1.0.1" }, "devDependencies": { "concurrently": "^3.1.0", "cpx": "^1.5.0", "rimraf": "^2.5.4", "browser-sync": "^2.18.5", "typescript": "^2.1.4", "@types/office-js": "^0.0.37", "@types/jquery": "^2.0.39", "@types/angular": "^1.6.2" } }
The merged file is:
{
"name": "sample-add-in",
"description": "",
"author": "",
"version": "0.1.0",
"scripts": {
"tsc": "tsc -p tsconfig.json -w",
"server": "browser-sync start --config bsconfig.json",
"copy": "cpx \"src/**/!(*.ts)\" dist --watch",
"start": "rimraf dist && concurrently \"npm run tsc\" \"npm run copy\" \"npm run server\"",
"validate": "./node_modules/.bin/validate-office-addin",
"ng": "ng",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"dependencies": {
"@angular/animations": "^6.0.0",
"@angular/common": "^6.0.0",
"@angular/compiler": "^6.0.0",
"@angular/core": "^6.0.0",
"@angular/forms": "^6.0.0",
"@angular/http": "^6.0.0",
"@angular/platform-browser": "^6.0.0",
"@angular/platform-browser-dynamic": "^6.0.0",
"@angular/router": "^6.0.0",
"core-js": "^2.5.4",
"rxjs": "^6.0.0",
"zone.js": "^0.8.26",
"office-ui-fabric-js": "^1.3.0",
"jquery": "^3.1.1",
"office-addin-validator": "^1.0.1"
},
"devDependencies": {
"@angular/compiler-cli": "^6.0.0",
"@angular-devkit/build-angular": "~0.6.0",
"typescript": "~2.7.2",
"@angular/cli": "~6.0.0",
"@angular/language-service": "^6.0.0",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "~4.2.1",
"jasmine-core": "~2.99.1",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~1.7.1",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~1.4.2",
"karma-jasmine": "~1.1.1",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.3.0",
"ts-node": "~5.0.1",
"tslint": "~5.9.1",
"concurrently": "^3.1.0",
"cpx": "^1.5.0",
"rimraf": "^2.5.4",
"browser-sync": "^2.18.5",
"@types/office-js": "^0.0.37",
"@types/jquery": "^2.0.39",
"@types/angular": "^1.6.2"
}
}
Yet, when I run npm start
I get these errors from the main page:
Refused to apply style from 'https://localhost:3000/node_modules/angular/angular-csp.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
angular.js:1 Failed to load resource: the server responded with a status of 404 (Not Found)
Refused to execute script from 'https://localhost:3000/node_modules/angular/angular.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
app.ts:9 Uncaught ReferenceError: angular is not defined
at app.ts:9
at app.ts:43
o15apptofilemappingtable.debug.js:5530 Warning: Office.js is loaded outside of Office client
telemetryproxy.html:1 Failed to load resource: the server responded with a status of 404 ()
(index):1 Refused to apply style from 'https://localhost:3000/node_modules/angular/angular-csp.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
telemetryproxy.html:1 Failed to load resource: the server responded with a status of 404 ()
Approach 2
Thus I tried the inverse approach, which happens to be suggested at https://github.com/Hongbo-Miao/office-addin-quick-start (I had to change something).
create a new angular app:
ng new sample-addin
enter its directory, and launch the office toolbox:
office-toolbox
. Generate the manifest (create a subfolder: NO, create a new addin: NO). This will overwrite some files, so before proceeding make a copy of the ones which require merging:package.json
: copy before overwriting.tsconfig.json
: do not overwrite, it's identical.index.html
: just overwrite.
in
index.html
, add before thehead
closing tag:in
main.ts
replace this:
platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.log(err));
with:
declare const Office: any; Office.initialize = () => { platformBrowserDynamic().bootstrapModule(AppModule) .catch(err => console.log(err)); };
- merge the missing content from the saved copy of package.json, replacing old Angular packages and Typescript references and adding all the missing, Angular related packages. Sample:
{ "name": "sample-add-in", "description": "", "author": "", "version": "0.1.0", "scripts": { "tsc": "tsc -p tsconfig.json -w", "server": "browser-sync start --config bsconfig.json", "copy": "cpx \"src/**/!(*.ts)\" dist --watch", "start": "rimraf dist && concurrently \"npm run tsc\" \"npm run copy\" \"npm run server\"", "validate": "./node_modules/.bin/validate-office-addin", "ng": "ng", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "dependencies": { "@angular/animations": "^6.0.0", "@angular/common": "^6.0.0", "@angular/compiler": "^6.0.0", "@angular/core": "^6.0.0", "@angular/forms": "^6.0.0", "@angular/http": "^6.0.0", "@angular/platform-browser": "^6.0.0", "@angular/platform-browser-dynamic": "^6.0.0", "@angular/router": "^6.0.0", "core-js": "^2.5.4", "rxjs": "^6.0.0", "zone.js": "^0.8.26", "jquery": "^3.1.1", "office-addin-validator": "^1.0.1", "office-ui-fabric-js": "^1.5.0" }, "devDependencies": { "@angular/compiler-cli": "^6.0.0", "@angular-devkit/build-angular": "~0.6.0", "typescript": "~2.7.2", "@angular/cli": "~6.0.0", "@angular/language-service": "^6.0.0", "@types/jasmine": "~2.8.6", "@types/jasminewd2": "~2.0.3", "@types/node": "~8.9.4", "codelyzer": "~4.2.1", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~1.7.1", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~1.4.2", "karma-jasmine": "~1.1.1", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.3.0", "ts-node": "~5.0.1", "tslint": "~5.9.1", "concurrently": "^3.1.0", "cpx": "^1.5.0", "rimraf": "^2.5.4", "browser-sync": "^2.18.5", "@types/office-js": "^0.0.37", "@types/jquery": "^2.0.39", "@types/angular": "^1.6.2" } }
- if you are using Windows, since the add-in platform uses Internet Explorer, uncomment these lines in
polyfills.ts
:
import 'core-js/es6/symbol'; import 'core-js/es6/object'; import 'core-js/es6/function'; import 'core-js/es6/parse-int'; import 'core-js/es6/parse-float'; import 'core-js/es6/number'; import 'core-js/es6/math'; import 'core-js/es6/string'; import 'core-js/es6/date'; import 'core-js/es6/array'; import 'core-js/es6/regexp'; import 'core-js/es6/map'; import 'core-js/es6/weak-map'; import 'core-js/es6/set';
This too fails on load with similar errors.