Giter VIP home page Giter VIP logo

babel-plugin-transform-named-imports's Introduction

babel-plugin-transform-named-imports

MIT licensed npm version Build Status Code Coverage

This plugin attempts to transform named ES6 imports to default imports:

// from this
import { myFunc } from 'mymodule';

// to this
import myFunc from 'node_modules/mymodule/myFunc';

The former causes mymodule/index.js to be imported, and therefor all other classes and methods to be imported as well. By transforming the import, tree shaking is far more effective and you can be assured that code that you're not using does not end up in your bundle.

Warning

This plugin aggressively transforms all imports thay pass to Babel. If you have any index.js files that have side effects, i.e code that executes on import, do not use this plugin. That code will never make it into your bundle with this plugin. To be on the safe side, do not run your node_modules through Babel. It might cause problems with libraries that rely on the behavior described above.

This is not a silver bullet. If your code does not rely on side effects, then you can expect this plugin to work well. If you do have code with side effects, then we strongly recommend that you do not use this plugin.

Why?

When you use a named export, Webpack actually pulls in the entire module. It should tree shake the things you don't actually use, leaving you with only what you actually use.

Unfortunately, Webpack often decides not to remove something because of potential side effects. By always importing from the file the function/class was declared in, you could avoid accidentely pulling in a large module. This would make importing very cumbersome.

This plugin attempts to rewrite your imports to always import from the file in which the function/class was declared in.

Installation

  1. Install the package from NPM:

     yarn add --dev babel-plugin-transform-named-imports
    
  2. Add transform-named-imports to your Babel configuration:

     "plugins": [
         "transform-named-imports": {
             "webpackConfig": "./webpack.config.js",
             "webpackConfigIndex": 0
         }
     ]
    

    Alternatively, pass a Webpack configuration object instead:

     "plugins": [
         "transform-named-imports" {
             "webpackConfig": {
                 "resolve": {
                     "alias": {
                         "~": "./test"
                     }
                 }
             }
         }
     ]
    

Workings

  1. Given a file that looks like this:

     import { myFunc } from 'myModule';
    
  2. For every import statement, resolve the full path to mymodule and parse the file:

     import myFunc from './myFunc';
    
     export { myFunc };
    
  3. Analyze the imports/exports in the resolved file and keep recursing until the file is found in which myFunc was declared.

  4. Rewrite the original import to lead to the file in which myFunc was declared:

     import myFunc from 'node_modules/mymodule/myFunc.js';
    

FAQ

  1. Why is my webpack configuration required?

    In order for the plugin to find the file in which a function/class was declared, the plugin has to resolve imports. Babel itself doesn't concern itself with importing, just rewriting code. Your webpack configuration is required so the plugin can resolve paths exactly how they're supposed to be resolved.

  2. Does this handle aliases?

    Yes.

  3. Can I exclude certain paths?

    No.

  4. Does it transform CommonJS imports?

    No.

  5. Is it safe to run on any code base?

    There could be side-effects. If you're relying on a index.js being imported and executed, then this might screw that behavior. It could also be that there are third-party packages which this does not play nice with. If you have a reasonably clean code base that doesn't do anything out of the ordinay and doesn't pass node_modules through Babel, then this plugin will most likely work for you.

  6. By how much will it decrease my bundle size?

    This highly depends on how large the modules are you are importing from and how much of it you actually use. The improvements are more visible in code bases that split their bundle into chunks or have multiple endpoints.

Debugging

Some more detailed logging is available when using the DEBUG environment variable:

DEBUG=transform-named-imports some-command-that-runs-transpilation

Thanks

Thanks to the author of babel-plugin-transform-imports for the initial idea of rewriting the imports.

The major difference with babel-plugin-transform-imports is that it requires defining every module you want rewritten. This plugin goes a step further and rewrites all your imports.

babel-plugin-transform-named-imports's People

Contributors

evan-scott-zocdoc avatar photonios avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

babel-plugin-transform-named-imports's Issues

Error: Plugin/Preset files are not allowed to export objects, only functions.

ERROR in ./react-entry.js
Module build failed: Error: Plugin/Preset files are not allowed to export objects, only functions. In /Users/Jan/Sites/gyana-ai-client/src/react/node_modules/babel-plugin-transform-named-imports/src/index.js
    at createDescriptor (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:181:11)
    at /Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:106:12
    at Array.map (<anonymous>)
    at createDescriptors (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:105:27)
    at createPluginDescriptors (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:101:10)
    at /Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:52:19
    at plugins (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-descriptors.js:42:25)
    at mergeChainOpts (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-chain.js:322:68)
    at /Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-chain.js:277:7
    at buildRootChain (/Users/Jan/Sites/gyana-ai-client/src/react/node_modules/@babel/core/lib/config/config-chain.js:111:20)
 @ multi ./react-entry webpack-hot-middleware/client?path=http://localhost:3000/__webpack_hmr webpack/hot/only-dev-server react-hot-loader/patch
ℹ 「wdm」: Failed to compile.
Webpack Bundle Analyzer is star

Handle glob imports

First, great idea! I was excited to see this 😄

One issue came up when I tried to run it over our codebase: the plugin doesn't know to opt-out of trying to trace namespace / "glob" imports like:

import * as something from './somewhere';

Handle renaming of imports

With a file chain like:

// index.js
import { PlansView } from './Items';

// Items/index.js
import { PlansConnector as PlansView } from './PlansConnector';

export { PlansView };

// PlansConnector/index.js
export const PlansConnector = connect(
    mapStateToProps,
    mapDispatchToProps
)(ItemsView);

The plugin is still looking for "PlansView" when it gets to PlansConnector/index.js, which won't exist since the import was renamed.

I imagine renaming default probably wouldn't work either under the current implementation.

incorrect handling of namespace renamed export

The program searches for import with the candidate name first, then if not found, it will look for re-export.

This logic has a problem: for example,
testmodule/index.js
import myFunc from './myFunc';
import { myOtherOtherFunc } from './reexport';
import * as things from './constants';

export {
myFunc,
myOtherOtherFunc as myOtherFunc,
things as thangs,
myFunc as things,
};

When the program searches for import of things, it will convert a import string

import { things } from 'testmodule',

into

import * as things from './tests/testmodule/constants',

while infact, it should be

import things from './tests/testmodule/myFunc'

Another problem of this logic is:
It does not handle export from syntax

If testmodule/index.js contains

export {Foo2} from '/Foo.js';

The program could not find it because the re-export it handles must be separate import and export.

PR #7

Caching?

For large codebases, this plugin ends up being a little slow since it might re-resolve a popular file many times. It might make sense to set up some sort of cache that can be shared between instances of the loader.

A possible implementation idea:

cache key = directory context + required path
cache value = resolved path

So for the file /Users/Someone/code/project/src/blah/blah/blah/index.js containing:

import { Foo } from '../../index.js';

The cache entry would look like:

'/Users/Someone/code/project/src/blah/blah/blah:../../index.js': '/Users/Someone/code/project/src/blah/index.js'

(the colon seems to invalid in most file systems, so a good candidate for a delimiter)

Then all siblings to /Users/Someone/code/project/src/blah/blah/blah/index.js could make use of the cache. With some finessing, it might be possible for the cache to be usable by children in other directory contexts...

Incorrect Babylon plugins in `ast`.

The current Babylon configuration breaks when analyzing a file that uses the export * as newName from '...' syntax. It looks like Babylon has since split exportExtensions into two different plugins: exportDefault and exportNamespace.

In my testing, everything works correctly if the exportExtensions plugin is replaced with the two new plugins in src/ast.js.

Speaking of the export-namespace syntax, are there any plans to support it in this plugin?

Support Webpack's `sideEffects` property in `package.json`.

When it comes to the problem of side-effects, Webpack has a means of marking specific files as having them through a property on the module's package.json file.

This could be used by this plugin as an indicator to use a more rigorous processing method on them or ignore them entirely.

It is a little complex, though, as you would need to check not only the current project's package.json file, but also those of any other node_modules that may have been included by the current project.

It also is a bit dependent on other node_modules properly using this Webpack feature. Perhaps allow some configuration for a strictSideEffects mode, where any module that lacks the sideEffects property is assumed to have them and ignored by this plugin.

More ways to load the webpack config

First, thanks for the great concept and good work done so far! 🎉

Problem

I am using nextjs in my application, which doesn't let me have a webpack configuration stored as a simple ./webpack.config.js. Instead, it let me expand its default webpack settings by defining a webpack key in the exported object of the file next.config.js. The final webpack config is generated in runtime by nextjs itself.

Questions

  • What others ways could I define the webpack config in babel-plugin-transform-named-imports?
  • Would you have any idea of how we could make tools like nextjs work well with it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.