Skip to content

Lerna + Webpack + Multiple entry points for fullstack packages #3006

@eric-burel

Description

@eric-burel

Expected Behavior

Hi, I am working on transitionning Meteor packages to NPM.

In Meteor, you have the possibility to create full-stack packages quite easily, by creating client and server package.
This behaviour is surprisingly hard to reproduce with bare NPM packages structured in a Lerna repo and built with Webpack.

My dream setup:
Files would be like this:

client/index.ts
server/index.ts
index.ts
package.json

Then imports are like this:

import { serverOnly } from "my-fullstack-package/server"

I have 2 or 3 build steps: one for shared code, one for client-only code, one for server-only code.

Current Behavior

First difficulty: at the time of writing TypeScript doesn't support multiple entry points in NPM packages, so you have to use an hackish solution with typings (see https://stackoverflow.com/questions/63058081/package-json-with-multiple-entrypoints).
But that's not really related to Lerna so let's ignore this.

My package.json looks like this:

{
  "name": "@vulcanjs/mongo",
  "main": "./dist/index.js",
  "files": [
    "dist/"
  ],
  "exports": {
    ".": "./dist/index.js",
    "./client": "./dist/client/index.js"
  },
  "types": "./dist/index.d.ts",
  "typesVersions": {
    "*": {
      "client": [
        "./dist/client/index.d.ts"
      ]
    }
  },

It works ok, I can import client-only code from downstream apps correctly.

Second difficulty: when I mistakenly import a relative path of a local package, I end up with multiple folders in my build.

Like import foobar from "other-package/foobar" will get the following result in the build of my-package:

dist/other-package
dist/my-package

Instead of having directly:

dist/index.js # from my-package

This seems to be an expected behaviour, usually I solve this by removing all those "local" imports and fixing my exports.
However, my problem is that I also have this behaviour when importing one of my entry points, like other-package/client. This time, client is not a nested file, but an actual entry point.

Possible Solution

First, having better explanation about what happens when mixing Lerna and Webpack. Maybe the issue is easy to fix, but I fail to find documentation in the wild. It's not very clear what happens/what is supposed to happen in those scenarios.

I seem to be able to trick Webpack by creating a fake, wrong alias for the external package with multiple entry points => it will prevent it to try to build the external package.

resolve: {
    alias: {
       "other-package/server": "not_found" // doesn't seem to affect the build, Webpack simply ignore the package
   }
}
lerna.json

{
  "version": "0.4.0",
  "npmClient": "yarn",
  "useWorkspaces": true,
  "packages": [
    "packages/*"
  ],
  "command": {
    "publish": {
      "ignoreChanges": [
        "*.md"
      ]
    }
  }
}

lerna-debug.log

<!-- If you have a `lerna-debug.log` available, please paste it here -->
<!-- Otherwise, feel free to delete this <details> block -->

Context

I have a (non-minimal) open source setup: https://github.com/VulcanJS/vulcan-npm

Your Environment

Executable Version
lerna --version 3.22
npm --version VERSION
yarn --version 1.22.5
node --version 14.17.5
OS Version
NAME VERSION

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions