Skip to content

An alternative to relative imports for local source code #40446

@epixa

Description

@epixa

The problem

Today, we import local source code with many different path formats. Client-side code can use webpack aliases, TypeScript can import from kibana, ui, or plugins (technically on either server or client), server-side JavaScript can only do relative imports.

This is a burden for us, so we agreed to fix it. Since relative imports are usable anywhere (in theory), we decided all imports should be done through relative imports. This solves the consistency problem, but it introduces others.

Relative imports across module/package/plugin boundaries inherently make those modules less portable if the system around them changes. A great example of this is the recent move of the legacy plugins, which involved updating hundreds of import paths despite the intention of those import statements remaining unchanged.

Relative imports create ambiguity with similarly named files and directories. e.g. At a glance, does import from '../../../../../../tests' import from the root level tests directory or from the tests directory inside your plugin? The deeper your code is nested, the harder that question is to answer. It's not purely visual as well, as you can't really use find+replace to identify this either.

Relative imports make many developers unhappy. There has been strong push back on relative imports for sharing code across plugins, especially from folks that do most of their development in the browser where they're used to convenient webpack aliases.

Finally, the assumption we made when adopting a relative imports strategy that they are available in all contexts is not accurate. Despite them seeming like the standard import mechanism, developers have run into issues in various places (e.g. mocks in tests) when trying to do relative imports.

Proposed solution

Code should be imported from outside the current package/system/plugin using imports from Kibana root.

Within a package/system/plugin, it's appropriate to use relative imports, though absolute imports are still acceptable when the relative import is still crazy. Most developers will do this anyway given the option.

So for example, any of these options would be OK from within a plugin called "foo":

/*
src
  plugins
    foo
      bar
        whatever.js
      test_utils
        foomocks.js
test_utils
  globalmocks.js
*/

// src/plugins/foo/bar/whatever.js

// OK
import from 'test_utils/globalmocks';
import from 'src/plugins/foo/test_utils/foomocks';
import from '../test_utils/foomocks';

// NOT OK
import from '../../../test_utils/globalmocks';

I have a proof of concept for supporting this import behavior in #40066. More work is required, like updating the webpack configuration for client-side code and getting CI passing, but overall I think this is very doable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Team:CorePlatform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t//discussstaleUsed to mark issues that were closed for being stale

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions