Office-js: Running `npm run build` creates and then deletes functions.json file

Created on 11 May 2020  路  10Comments  路  Source: OfficeDev/office-js

Expected Behavior


When I run npm run build to build my add-in it's supposed to generate a JSON file for the custom functions I created.

Current Behavior



For whatever reason, when I run npm run build it returns the following error:

C:\Users\Alex\OneDrive\Desktop\new-office-add-in> npm run build

> [email protected] build C:\Users\Alex\OneDrive\Desktop\new-office-add-in
> webpack -p --mode production --https false

C:\Users\Alex\OneDrive\Desktop\new-office-add-in\dist\functions.json created for file: 
C:\Users\Alex\OneDrive\Desktop\new-office-add-in\src\functions\functions.ts

Error: ENOENT: no such file or directory, stat 
'C:\Users\Alex\OneDrive\Desktop\new-office-add-in\dist\functions.json'

npm ERR! code ELIFECYCLE
npm ERR! errno 1

npm ERR! [email protected] build: `webpack -p --mode production --https false`
npm ERR! Exit status 1

npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\Alex\AppData\Roaming\npm-cache\_logs\2020-05-11T04_21_41_522Z-debug.log

The strange thing is I see the file gets created, but it is deleted immediately after it was created.

Steps to Reproduce, or Live Example



Context



Ideally, I would like to generate the custom functions in my Add-In and then use it with the task pane. Right now, I can't test or do any further development for my add-in until I can get past this obstacle.

Your Environment

  • Platform [PC desktop, Mac, iOS, Office Online]: PC Desktop
  • Host [Excel, Word, PowerPoint, etc.]: Excel
  • Office version number: 16.0.12829.20000
  • Operating System: Windows 10 1909
  • Browser (if using Office Online): N/A

Useful logs

DevX custom functions Needs

Most helpful comment

I wanted to leave this here in case anyone comes across this issue again. I believe I was able to fix the issue on the different types of Office Add-Ins regardless of whether you choose to use a react, angular, or a regular HTML Add-in. To incorporate custom functions into your add-in there are a few things you need to do:

Step 1: Modify the Folder Structure:

The first thing you need to do is modify your folder structure so that you can include the necessary files needed to create some functions.

  1. Create a folder inside of the src folder called functions.
  2. Inside of the functions folder, assuming you're using typescript then create a functions.html file and functions.ts file.

I found that you can use the same functions files provided by the repo that demonstrates how to use custom functions in Excel.

Step 2: Modify the Manifest.xml file:

By default, the manifest file is not set up to use the CustomFunctionsRuntime. To enable this and to allow you to use custom functions inside of your project you need to do the following:

  1. Add a requirements tag that specifies using the CustomFunctionsRuntime. It should look something like the following:
<!-- ADD THIS FOR FUNCTIONS -->
<Requirements>
    <Sets DefaultMinVersion="1.1">
        <Set Name="CustomFunctionsRuntime" MinVersion="1.1"/>
    </Sets>
</Requirements>
  1. Add a AllFormFactors tag if it doesn't exist, and then specify the extension point is for `CustomFunctions. It should look something like the following:
<!-- ADD THIS FOR FUNCTIONS -->
<AllFormFactors>
    <ExtensionPoint xsi:type="CustomFunctions">
        <Script>
            <SourceLocation resid="Functions.Script.Url"/>
        </Script>
        <Page>
            <SourceLocation resid="Functions.Page.Url"/>
        </Page>
        <Metadata>
            <SourceLocation resid="Functions.Metadata.Url"/>
        </Metadata>
        <Namespace resid="Functions.Namespace"/>
    </ExtensionPoint>
</AllFormFactors>
  1. Specify the source locations of the files used in the AllFormFactors tag. In the bt:urls tag add the following:
<!-- ADD THIS FOR FUNCTIONS -->
<bt:Url id="Functions.Script.Url" DefaultValue="https://localhost:3000/dist/functions.js"/>
<bt:Url id="Functions.Metadata.Url" DefaultValue="https://localhost:3000/dist/functions.json"/>
<bt:Url id="Functions.Page.Url" DefaultValue="https://localhost:3000/dist/functions.html"/>

and in the bt:ShortStrings tag add the following:

<!-- ADD THIS FOR FUNCTIONS -->
<bt:String id="Functions.Namespace" DefaultValue="MY_CUSTOM_FUNCTIONS"/>

Step 4: Install the dependencies using `npm

You'll need a few more packages than what is listed in the package.json file. The first one is the clean-webpack-plugin, it will more than look like the following under the devDependencies group:

"clean-webpack-plugin": "^3.0.0"

At the time of writing this, the 3.0.0 version will not work with custom functions, so you need to revert to an earlier version. Right now, I verified that version 2.1.0 will work so make sure it looks like the following:

"clean-webpack-plugin": "^2.0.1"

You may need to uninstall the previous version and then reinstall it:

npm uninstall clean-webpack-plugin
npm install

You'll also need the following other packages added to your dependencies:

"custom-functions-metadata-plugin": "^1.0.26"
"@types/custom-functions-runtime": "^1.5.0"

Step 4: Modify the webpack.config.js File

Inside of the webpack.config.js file, you'll need to add a few more imports and add a few more plugins. The imports you'll need are the following:

// MODIFY THIS FOR FUNCTIONS.
const CleanWebpackPlugin = require("clean-webpack-plugin");

// ADD THIS FOR FUNCTIONS.
const CustomFunctionsMetadataPlugin = require("custom-functions-metadata-plugin");

Under the plugins section it should look like the following:

// MODIFY THIS FOR FUNCTIONS.
  new CleanWebpackPlugin({
    cleanOnceBeforeBuildPatterns: dev ? [] : ["**/*"]
  }),

  new HtmlWebpackPlugin({
    filename: "taskpane.html",
    template: "./src/taskpane/taskpane.html",
    chunks: ["polyfill", "taskpane"]
  }),

  // ADD THIS FOR FUNCTIONS.
  new CustomFunctionsMetadataPlugin({
    output: "functions.json",
    input: "./src/functions/functions.ts"
  }),

  // ADD THIS FOR FUNCTIONS.
  new HtmlWebpackPlugin({
    filename: "functions.html",
    template: "./src/functions/functions.html",
    chunks: ["polyfill", "functions"]
  }),

  new CopyWebpackPlugin([
    {
      to: "taskpane.css",
      from: "./src/taskpane/taskpane.css"
    }
  ]),

  new HtmlWebpackPlugin({
    filename: "commands.html",
    template: "./src/commands/commands.html",
    chunks: ["polyfill", "commands"]
  })

Once you've done this, you've made all the necessary changes.

Step 5: Build and Run the Project

Before you run the project, you need to run the build process so that way the functions.json file is produced. Assuming you're in the main folder, from the console run the following command:

npm run build

Inside of the dist folder, you should see the files there more specifically you should be looking for functions.json file, functions.js, functions.html, and functions.js.map file.

If you see those files that's a good sign, so you should be able to start the project. From the console run the following command:

npm start

Closing Remarks

Ideally, if you take those steps it should allow you to use custom functions in your project. You really need to make sure you do the following:

  1. Create the folder
  2. Modify the manifest file.
  3. Make sure you have the dependencies.
  4. Build & Run the project.

If any has any other insights or if they can find ways to simplify or enhance this process please feel free to share it because right now there doesn't seem to be any source of documentation on incorporating custom functions into an existing add-in project.

All 10 comments

Hi there,

I was hoping to get an update on this and see if there has been any headway made on this?

Hey @RuoyingLiang , can you provide more context regarding the JSON file generation for custom functions?

If you clone the https://github.com/OfficeDev/Excel-Custom-Functions repository and check out the "yo-office" branch, then run npm install and npm run build, this should build successfully.

It would be good to see what is different with the package.json dependencies and the webpack config.

Also, did you start with the React taskpane template and then add custom-functions to it? The package.json name appears to be office-addin-taskpane-react. That's fine, but I am just wondering.

Adding @TCourtneyOwen for visibility.

@akrantz I did start with a react template and then added the custom functions folder to it. From there, I started going through and comparing dependencies to see which ones I needed.

From my understanding, these were the ones I needed:

"custom-functions-metadata-plugin": "^1.0.26"
"@types/custom-functions-runtime": "^1.5.0"

Webpack Plugin

However, after exploring GitHub, I found out that the issue was related to this package:

"clean-webpack-plugin": "^3.0.0"

Inside of the react template, you'll notice it's ^3.0.0 but in the excel-custom-function template it's this one:

"clean-webpack-plugin": "^2.0.1"

For whatever, reason version 2.0.1 can successfully generate the funcitons.json file. Version 3.0.0 will error out and does not work with custom-functions-metadata-plugin.

The odd thing is if I use the package custom-functions-metadata that's inside of custom-functions-metadata-plugin I can manually create the functions.json file by running the following command:

node C:\Users\Alex\OneDrive\Desktop\new-office-add-in\node_modules\custom-functionsmetadata\lib\cli.js generate "C:\Users\Alex\OneDrive\Desktop\new-office-add-in\src\functions\functions.ts" "C:\Users\Alex\OneDrive\Desktop\new-office-add-in\dist\functions.json"

For more info on this, I went to this repo: Office-Addin-Scripts

Running the add-in

When I run the add-in with npm start, it does run successfully, but the functions don't seem to load correctly. From my experience, there can be a whole range of issues that prevent them from being installed correctly. I started going through the more obvious things that could cause the issue:

  1. Clearing the office cache.
  2. Validate the function's syntax.

Neither of these, fixed the issue. The functions work in my other project no problem and the clearing the caches didn't fix it either. I'm going to go through the following steps next:

  1. Validate the manifest file.
  2. Looking through the output in the dist folder.

Is there a better way to go about this? For example, is there pre-built functionality I can leverage that will help validate the project beyond the manifest file?

@areed1192 Were you ever able to get this working? I'm running into the same thing now, trying to get a React-based taskpane + custom functions. The suggestion to downgrade clean-webpack-plugin worked, but I'm in the same boat with the add-in starting but the functions not being loaded.

I'm really surprised this doesn't work out of the box. It feels like this would be a pretty common use-case.

Update: was able to fix my issue. I typo'd Runtime as Runtimes in my manifest. Enabling runtime logging led me to the answer:

https://docs.microsoft.com/en-us/office/dev/add-ins/testing/runtime-logging

(And in case that page gets moved/deleted, since that seems to happen a lot with the add-in docs, here's the short version)
run npx office-addin-dev-settings runtime-log --enable
tail your log at %LOCALAPPDATA%\Temp\OfficeAddins.log.txt

I wanted to leave this here in case anyone comes across this issue again. I believe I was able to fix the issue on the different types of Office Add-Ins regardless of whether you choose to use a react, angular, or a regular HTML Add-in. To incorporate custom functions into your add-in there are a few things you need to do:

Step 1: Modify the Folder Structure:

The first thing you need to do is modify your folder structure so that you can include the necessary files needed to create some functions.

  1. Create a folder inside of the src folder called functions.
  2. Inside of the functions folder, assuming you're using typescript then create a functions.html file and functions.ts file.

I found that you can use the same functions files provided by the repo that demonstrates how to use custom functions in Excel.

Step 2: Modify the Manifest.xml file:

By default, the manifest file is not set up to use the CustomFunctionsRuntime. To enable this and to allow you to use custom functions inside of your project you need to do the following:

  1. Add a requirements tag that specifies using the CustomFunctionsRuntime. It should look something like the following:
<!-- ADD THIS FOR FUNCTIONS -->
<Requirements>
    <Sets DefaultMinVersion="1.1">
        <Set Name="CustomFunctionsRuntime" MinVersion="1.1"/>
    </Sets>
</Requirements>
  1. Add a AllFormFactors tag if it doesn't exist, and then specify the extension point is for `CustomFunctions. It should look something like the following:
<!-- ADD THIS FOR FUNCTIONS -->
<AllFormFactors>
    <ExtensionPoint xsi:type="CustomFunctions">
        <Script>
            <SourceLocation resid="Functions.Script.Url"/>
        </Script>
        <Page>
            <SourceLocation resid="Functions.Page.Url"/>
        </Page>
        <Metadata>
            <SourceLocation resid="Functions.Metadata.Url"/>
        </Metadata>
        <Namespace resid="Functions.Namespace"/>
    </ExtensionPoint>
</AllFormFactors>
  1. Specify the source locations of the files used in the AllFormFactors tag. In the bt:urls tag add the following:
<!-- ADD THIS FOR FUNCTIONS -->
<bt:Url id="Functions.Script.Url" DefaultValue="https://localhost:3000/dist/functions.js"/>
<bt:Url id="Functions.Metadata.Url" DefaultValue="https://localhost:3000/dist/functions.json"/>
<bt:Url id="Functions.Page.Url" DefaultValue="https://localhost:3000/dist/functions.html"/>

and in the bt:ShortStrings tag add the following:

<!-- ADD THIS FOR FUNCTIONS -->
<bt:String id="Functions.Namespace" DefaultValue="MY_CUSTOM_FUNCTIONS"/>

Step 4: Install the dependencies using `npm

You'll need a few more packages than what is listed in the package.json file. The first one is the clean-webpack-plugin, it will more than look like the following under the devDependencies group:

"clean-webpack-plugin": "^3.0.0"

At the time of writing this, the 3.0.0 version will not work with custom functions, so you need to revert to an earlier version. Right now, I verified that version 2.1.0 will work so make sure it looks like the following:

"clean-webpack-plugin": "^2.0.1"

You may need to uninstall the previous version and then reinstall it:

npm uninstall clean-webpack-plugin
npm install

You'll also need the following other packages added to your dependencies:

"custom-functions-metadata-plugin": "^1.0.26"
"@types/custom-functions-runtime": "^1.5.0"

Step 4: Modify the webpack.config.js File

Inside of the webpack.config.js file, you'll need to add a few more imports and add a few more plugins. The imports you'll need are the following:

// MODIFY THIS FOR FUNCTIONS.
const CleanWebpackPlugin = require("clean-webpack-plugin");

// ADD THIS FOR FUNCTIONS.
const CustomFunctionsMetadataPlugin = require("custom-functions-metadata-plugin");

Under the plugins section it should look like the following:

// MODIFY THIS FOR FUNCTIONS.
  new CleanWebpackPlugin({
    cleanOnceBeforeBuildPatterns: dev ? [] : ["**/*"]
  }),

  new HtmlWebpackPlugin({
    filename: "taskpane.html",
    template: "./src/taskpane/taskpane.html",
    chunks: ["polyfill", "taskpane"]
  }),

  // ADD THIS FOR FUNCTIONS.
  new CustomFunctionsMetadataPlugin({
    output: "functions.json",
    input: "./src/functions/functions.ts"
  }),

  // ADD THIS FOR FUNCTIONS.
  new HtmlWebpackPlugin({
    filename: "functions.html",
    template: "./src/functions/functions.html",
    chunks: ["polyfill", "functions"]
  }),

  new CopyWebpackPlugin([
    {
      to: "taskpane.css",
      from: "./src/taskpane/taskpane.css"
    }
  ]),

  new HtmlWebpackPlugin({
    filename: "commands.html",
    template: "./src/commands/commands.html",
    chunks: ["polyfill", "commands"]
  })

Once you've done this, you've made all the necessary changes.

Step 5: Build and Run the Project

Before you run the project, you need to run the build process so that way the functions.json file is produced. Assuming you're in the main folder, from the console run the following command:

npm run build

Inside of the dist folder, you should see the files there more specifically you should be looking for functions.json file, functions.js, functions.html, and functions.js.map file.

If you see those files that's a good sign, so you should be able to start the project. From the console run the following command:

npm start

Closing Remarks

Ideally, if you take those steps it should allow you to use custom functions in your project. You really need to make sure you do the following:

  1. Create the folder
  2. Modify the manifest file.
  3. Make sure you have the dependencies.
  4. Build & Run the project.

If any has any other insights or if they can find ways to simplify or enhance this process please feel free to share it because right now there doesn't seem to be any source of documentation on incorporating custom functions into an existing add-in project.

@areed1192 Thanks for taking the time to share these details.

@mscharlock Is this something that should be documented? @akrantz @TCourtneyOwen Is this something that should be incorporated in the related templates?

Thanks.

@ElizabethSamuel-MSFT let me follow up with you offline :)

@areed1192 Thanks so much for that. I saw your videos as well, and must say that it's pretty much the most comprehensive resource for Office Add-Ins at the moment.

Was this page helpful?
0 / 5 - 0 ratings