A Witty Title

FortuneExcel - Lessons from my First Package

18 Nov 2024

I revived an archived project and released it as FortuneExcel - a plugin for FortuneSheet to import/export Excel (.xlsx) files.

Sections:

  1. Initialization
  2. Modularization
  3. Github Workflow
  4. Secrets and Tokens
  5. Commonjs Entrypoint
  6. Compiling TS for Storybook

Initialization

Reviving the project meant fixing the deprecated code and existing bugs. Along with this, I added export feature, toolbar plugin support for fortune-sheet and set up Github workflow.

Modularization

While implementing a package, it should have maximum abstraction. User should have to add minimal code to their environment for your package to work, all while having no side-effects on their existing code. A proper code strucrure also makes it easier for others to contribute to your code.

Github Workflow

Lets breakdown the pubhlish.yml file.

Run the workflow whenever a release is published or manually triggered from Actions tab:

publish.yml
-----------
on:
  release:
    types: [published]
  workflow_dispatch:

Define premissions required by the workflow:

permissions:
  contents: read
  pages: write
  id-token: write

Checkout the code, setup node environment, install dependencies (see npm i vs npm ci) and publish the package on npm:

    - uses: actions/checkout@v3
    - uses: actions/setup-node@v3
    with:
        node-version: "20.x"
        registry-url: "https://registry.npmjs.org"
    - run: npm ci
    - run: npm publish --tag latest --provenance --access public
    env:
        NODE_AUTH_TOKEN: $

Build the Storybook, upload it as an artifact and deploy it on GitHub Pages:

Note: Update Build and Deployement source to ‘Github Actions’ in repo > Settings > Pages

    - run: npm run build-storybook
    - uses: actions/upload-pages-artifact@v2
    with:
        path: storybook-static
    - id: deploy
    uses: actions/deploy-pages@v3
    with:
        token: $

Secrets and Tokens

In the above section inside publish.yml, notice github.token and secrets.NPM_TOKEN.

While github.token is automatically provided by GitHub Actions, secrets.NPM_TOKEN is an automation access token that has to be generated at npmjs.com and set as repository secret on Github.

Emitted Javascript version

Fortune-excel and fortune-sheet were having incompatibility issues due to different transmitted JS when compiled from TS. This is defined by the target value in compilerOptions of tsconfig.json. Since fortune-sheet compiles the JS In es5, changing the target from es6 to es5 in fortune-excel fixed the issue:

tsconfig.json
-----------
{
  "compilerOptions": {
    "target": "es5",
    ...
  }
}

Commonjs entrypoint

After publishing the package, Yarn showed this warning - ‘the package doesn’t seem to have a commonjs entry point’. Compiling the TS in commonjs is necessary for old projects still using CJS instead of ESM. Compiling is ESM is optional since EMS supports CJS, but not visa-versa. To fix the warning:

  1. Make sure package.json does not have "type": "module" defined

    When set to “module”, the type field allows a package to specify all .js files within are ES modules. If the “type” field is omitted or set to “commonjs”, all .js files are treated as CommonJS.

  2. Define "module": "commonjs" in tsconfig.json - refer to this.

Compiling TS for Storybook

To make our plugin work with Storybook in the same repository, we can take two approaches:

  1. Use the commonjs code inside /dist/ compiled by Typescript Compiler (tsc): the drawback of this is that it would be difficult to add breakpoints in the browser when testing the repo on storybook, as we are using the compiled code instead of the actual TS code.
  2. Use the actual typescript code: fixes the problem mentioned above

To use the actual TS code:

  1. Import the plugin in storybook example, and use an alias inside tsconfig.json:
    // tsconfig.json
    {
      "paths": {
         "@corbe30/fortune-excel": ["./src/main.ts"],
      },
      ...
    }
    
    // stories/Page.tsx
    import { exportToolBarItem, importToolBarItem } from "@corbe30/fortune-excel";
    
  2. Now, although the storybook is referring to /src/main.ts to import the plugin, building the storybook will throw a TS compilation error. This is because Storybook uses its own compiler separate from our project’s compliler, Babel. To ensure Babel is configured to handle TypeScript, Babel configuration (babel.config.js or .babelrc) should include the TypeScript preset:
     {
       "presets": [
         "@babel/preset-env",
         "@babel/preset-react",
         "@babel/preset-typescript"
       ],
       ...
     }
    

    Then install the necessary Babel presets:

     npm install --save-dev @babel/preset-env @babel/preset-react @babel/preset-typescript