Agregar Custom Functions a un proyecto de Office.js + React

Aprende a agregar Custom Functions a un proyecto de Office.js con React
Excel Office.js

He estado trabajando con Office.js + React y me tocó implementar custom functions (funciones o fórmulas personalizadas de Excel como =LOQUESEA.ALGO() que se conectaran a un task pane (la barra de la derecha de Excel) en React pero no hay mucha información al respecto ya que es un proyecto inicializado, y pues, mucho menos en inglés.

Así que, me tocó aprender y para facilitarles la vida les comparto cómo hacerlo.

Lo primero es modificar el manifest.xml en el cual agregaremos lo siguiente:

<Requirements>
    <Sets DefaultMinVersion="1.1">
      <Set Name="CustomFunctionsRuntime" MinVersion="1.1"/>
    </Sets>
</Requirements>

Esto debajo de <Hosts><Host name="Workbook" /></Hosts>

Con esto ya estamos configurando que vamos a requerir el runtime para custom functions (cabe destacar, que usaremos un non-shared runtime, de esto hablaré en otra publicación después para saber cómo configurar un shared runtime y qué significa en Excel y Office.js)

Primer paso completo, segundo paso, necesitamos agregar el «AllFormFactors», esto dentro de <Hosts><Host xsi:type="Workbook"> normalmente debajo de, hay otro que dice <Runtime>, si no está ahí esta etiqueta, entonces agrega justo debajo de <Host xsi:type="Workbook"> pero si sí está, agrégala debajo de </Runtime> :

<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>

Listo el segundo paso, estamos más cerca… casi hasta abajo (normalmente) encontramos una etiqueta llamada <Resources> y dentro varias de <bt> buscaremos la que sea referente a <bt:Urls> ahí vamos a agregar las siguientes:

<bt:Url id="Functions.Script.Url" DefaultValue="https://localhost:3000/public/functions.js" />
<bt:Url id="Functions.Metadata.Url" DefaultValue="https://localhost:3000/public/functions.json" />
<bt:Url id="Functions.Page.Url" DefaultValue="https://localhost:3000/public/functions.html" />

Esto lo que hará será poner todo dentro de public para la versión de functions, cabe destacar que hasta donde sé, se puede poner sin public pero en este tutorial lo dejaremos así. Ustedes podrán hacer sus adaptaciones «al gusto».

Siguiente punto, dado que Excel no permite generar funciones personalizadas (custom functions) en su ambiente sin un namespace (espacio de nombres o prefijo) ocupamos que se configure, para ello dentro de <bt:ShortStrings> vamos a agregar el espacio de nombre que querramos y donde estarán todas nuestras funciones (hay algunos formatos como los que genera .NET en su VSTO que no requieren dicho prefijo, pero en Office.js sí se requiere, hasta donde sé), y se agregaría la siguiente línea:

<bt:String id="Functions.Namespace" DefaultValue="ASFO" />

Reemplacen ASFO por el prefijo que quieran, para que al final aparezca algo como: MI_PREFIJO.MI_FUNCION()

Ya que tenemos nuestro manifiesto actualizado, vamos a correr npm run validate para checar que lo pusieron bien… de ahí si todo está bien, vamos a instalar un par de dependencias:

npm i @types/custom-functions-runtime --save-dev
npm i custom-functions-metadata-plugin

Cabe destacar que la primera se puede guardar como devDependency y creo que incluso la segunda ya que no se integra oficialmente, pero yo las instalé así y por ahora dado que no le sé mucho «mientras me funcione»

Ahora dentro de tu carpeta src vamos a agregar una nueva carpeta llamada functions con 2 archivos (o 3 si tienes tests 😉 ):

functions
|-functions.html
|-functions.ts 

Considero que utilizan TypeScript, si no pues cámbienle la extensión a JS

Ya casi terminamos, ahora vamos a agregar el código de cada uno para ello en el html, agregaremos lo siguiente:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta http-equiv="Expires" content="0" />
    <title></title>
    <script src="https://appsforoffice.microsoft.com/lib/1.1/hosted/custom-functions-runtime.js" type="text/javascript"></script>
  </head>
  <body></body>
</html>

Y asimismo, vamos a agregar una función de pruebas en el archivo functions.ts:

/**
 * Descripción de lo que hace la función
 * @customfunction
 */
export function hola(): string {
  return 'Hola mundo';
}

Si usan JS y no TS quiten el : string … es SUPER importante que agreguen el comentario arriba con el @customfunction en el ya que si no, Office.js a la hora de transpilar no va a detectar que es una custom function, la descripción, hasta donde sé, es opcional.

Ya con esto podemos mandar llamar la función de la forma =ASFO.HOLA() (o =PREFIJO.NOMBRE_DE_LA_FUNCION() ) en este caso no consideramos parámetros eso lo veríamos en otro tutorial para checar más a fondo.

Ya teniendo esto ya casi terminamos. Vamos ahora a terminar con Webpack (ya que el Yeoman de Office.js en React usa Webpack lamentablemente)… Lo primero es que «hasta arriba» (o donde están los imports) agregaremos la siguientes líneas en el archivo webpack.config.js:

/* global require, module, process, __dirname */
const CustomFunctionsMetadataPlugin = require("custom-functions-metadata-plugin");
const path = require("path");

El comentario yo recomiendo ponerlo hasta mero arriba, y después poner entre las variables existentes lo que le sigue. Ya que tengamos esto más abajo del archivo agregaremos:

functions: "./src/functions/functions.ts",

Esta línea va justo dentro del índice entry abajito del commands: './src/commands/commands.ts. o puede ir en cualquier parte dentro de entry{}

Últimos dos cambios, dentro del índice plugins: [] vamos a agregar 2 nuevas opciones, pueden ir hasta abajo o arriba o donde quieran en realidad:

new CustomFunctionsMetadataPlugin({
  output: "functions.json",
  input: "./src/functions/functions.ts",
}),
new HtmlWebpackPlugin({
  filename: "functions.html",
  template: "./src/functions/functions.html",
  chunks: ["polyfill", "functions"],
}),

Esto nos permitirá cargar los archivos que requerimos de functions. Y dentro del CopyWebpackPlugin veremos que hay una opción para manifest*.xml debemos asegurarnos que luzca de la siguiente forma:

{
    from: 'manifest*.xml',
    to: '[name]' + '[ext]',
    transform(content) {
        if (dev) {
            return content;
        } else {
            return content.toString().replace(new RegExp(urlDev + "(?:public/)?", "g"), urlProd);
        }
    }
}

Normalmente solo se agrega la línea del else… esto pues para cuando estamos en productivo nos quite la línea de public/ y todo quede directamente en la raíz para el manifesto y con la URL de producción.

Cabe destacar, que, normalmente se hace un build de producción para este tipo de acciones pero no me voy a meter en todo esto ya que vamos a seguir con una base configurada simple y después ustedes adaptan, esto es mi formato así que bien pueden ignorar parte de estos cambios y hacerlo a su manera 😉

Ahora sí ya para finalizar, donde tenemos el índice devServer vamos a buscar (y cambiar si hace falta):

static: {
    directory: path.join(__dirname, "dist"),
    publicPath: "/public",
},

Y con esto la próxima vez que corramos npm start y cargue nuestro Excel para trabajar con el, podremos usar la función =ASFO.HOLA() y la celda mostrará «Hola mundo» en su lugar.

Si te gustó este tutorial, dale like y suscríbete y desactiva el fregado Adblock para que pueda ganar dinero y así le damos seguimiento a la parte de usar funciones con parámetros, funciones que acceden a la celda misma, tutorial para usar el Shared Runtime y qué significa y todo eso… y más acerca de Office.js y otras cosas de Angular y programación… y si no pues come tierra, mentira, gracias por leerme igual, hasta el próximo tutorial.

Total
0
Shares
Publicación anterior
husky pre-commit hook error github desktop windows

Reparar el error: husky – command not found in PATH en Github Desktop en Windows

Siguiente Publicación
javascript logo

Crea tu propio sistema simple de «Lambdas/Functions» con NodeJS fácilmente

Publicaciones Relacionadas