Skip to content

Monorepo rewrite #131

@B4nan

Description

@B4nan

As @mnmkng mentioned, would be good to split this into multiple packages and convert the repo to monorepo, so we do not need to use deep imports (which is in general a bad practice). It will also serve as a PoC for future monorepos like the SDK.

Proposal

There are several options, mostly dependent on package manager (e.g. we could use pnpm or yarn that truly support workspaces), but in the end we will still probably need lerna too. It will help mainly with release management and build orchestration.

Here is the proposed set of repositories (partially based on usage, partially on 3rd party dependencies):

Unfortunately we can't use package names like apify-shared/consts (forbidden by NPM), so it will have to be something like @apify-shared/consts.

  • @apify-shared/consts
    • consts.js
    • regexs.js
  • @apify-shared/log
    • log.js
    • log_consts.js
    • log_helpers.js
    • logger.js
    • logger_json.js
    • logger_text.js
  • @apify-shared/input_schema
    • input_schema.js
    • input_schema.json
    • intl.js
  • @apify-shared/git
    • git.js
  • @apify-shared/salesforce_client
    • salesforce_client.js
  • @apify-shared/datastructures
    • linked_list.js
    • list_dictionary.js
    • lru_cache.js
  • @apify-shared/markdown
    • markdown_renderers.js
    • marked.js
  • @apify-shared/utilities
    • exponential_backoff.js
    • health_checker.js
    • image_proxy_client.js
    • parse_jsonl_stream.js
    • streams_utilities.js
    • utilities.client.js
    • utilities.js
    • webhook_payload_template.js

Happy to hear suggestions about this, as I haven't seen much of the internal repos so this is mostly based on the SDK. This will have direct impact on breaking changes, so if there is a file that is worth having as a single file repository just because it is used extensibly, we should indeed do it that way, especially if its in client facing code.

We might also want to split some of the large files (e.g. the consts.js one is quite large).

Suggestions

TypeScript

Personally I would also use this opportunity to convert the repository to typescript. We already added automatic generation of types recently, but they are all based purely on JS inference, so not great in general. Also I do have a working setup of lerna with TS so it would actually be easier for me to set it up that way.

Removal of default exports

Another thing I don't like is the overusage of default exports. They just add complexity to the compiled code, and also reduces DX (find usage & go to declarations are buggy as they jump to the import line instead of the actual implementation, at least in WS). If we are fine with making some additional breaking changes, I'd suggest getting rid of them in most places (haven't checked much code, I could understand the one in log, if we need to export an instance, default export sounds like the right thing to do).

Removal of polyfills

The only present polyfill is startsWith - I believe its already the time when its safe to say ES6 is supported everywhere, so this should not be needed. Unless we have actual need for this, let's get rid of it.

Removal of underscore

It's the ES6 time, most of the helper methods are natively supported or easily implemented on very few LoC. Mostly used ones that are clearly not needed: isArray, mapObject, map, some, filter, extends (as per the docs its the same as Object.assign(), it's not recursive), also pretty much all of the is* methods can be replaced with single line variants (either typeof or instanceof). I'd probably keep it in the salesforce client package, as there it is used heavily, but most of the other usages are easy to replace.

Btw if you think underscore is a small dependency, it's not (also native methods will be always faster):

➜  apify-shared-js git:(master) ✗ npx howfat underscore
Dependencies: 0
Size: 880.22kb
Files: 503

Yarn workspaces

Personally a big fan of yarn (v1), using it for years and never did me wrong, and it makes a good tandem when combined with lerna. NPM recently added support for workspaces too, but from what I read, it's far from complete. Here is some reading about why it is good combination:

https://doppelmutzi.github.io/monorepo-lerna-yarn-workspaces/

With lerna we should be fine with NPM too (as it was supported way even before NPM added workspaces), so this is really just an open question. But as I mentioned above, I do have a working version of this and it also uses yarn workspaces, so doing it this way would ease the implementation for me (or better - remove some unknowns - it could be also as easy as with yarn).

Also worth reading: https://hyperfoo.io/posts/npm-7-workspaces-1

Alternative

We might also just add index.js file and reexport things from there, and instead of accessing apify-shared/consts we could do import { consts } from 'apify-shared'.

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