First, the question is elicited

React is a component. Common components will be stored under the SRC directory in the components directory. Here’s the problem: if the components are broken down much more, the number of files naturally increases, and we might see something like this when we use them:

A lot of documents are not looking big! Imagine if we could act like an ANTD component:

import {
    ReimburseDetail,
    ContactUs,
    HoverTips,
    CustomModal,
    ReimburseStatus
} from 'src-components'
Copy the code

How about that? Ah, there is a way!

Second, solve the problem

Plan a

  1. incomponentsCreate a new one in the directoryindex.jsImport all files in the directory and export them.
    / * * * '. / module to read a directory of * true whether subdirectories read * / \. Js $/ matching suffix for 'js' file * /
    const files = require.context('./module'.true./\.js$/)
    const modules = files.keys().reduce((modules, path) = > {
        // './app.js' => 'app'
        const name = path.replace(/^\.\/|.js$/g.' ')
        modules[name] = files(path).default
        return modules
    }, {})
    export default modules
    Copy the code
  2. Try it out: It works, but the packaging volume increases, and unused components are included.

Scheme 2

  1. Let’s try implementing a babel-plugin manually.

  2. We know that there is no such thing as loading on demand when importing a single file. When a file is exposed to multiple export files, it is no longer a single file. Once the file is referenced, all the files exposed in the file will be imported and packaged. So is there something we can do about it? Suppose I import a nonexistent package and export the desired component:

    • Obviously, it is not possible to import all packages
    • Obviously it’s not going to work, it’s going to compile an error

    With this in mind, we can manually modify its default compilation rules to do what we want. We need to intercept all the files that use our custom package name, extract the incoming component name, modify the compilation rules, and let the components that import the incoming package name participate in the separate import package, which can achieve our desired purpose.

  3. Come on, get your hands dirty. See the link to this article to see how the Babel-Plugin API works:

    // .babelrc
    {
        "plugins": [["./src/utils/my-plugin-import", {
                    "libraryName": "src-components"."alias": "@/components"}],... ] }Copy the code
    // src/utils/my-plugin-import.js
    const toLine = name= > {
        const str = name.replace(/([A-Z])/g."$1").toLowerCase()
        return str.split(The '-') [0]? str : str.slice(1)}module.exports = function ({ types: t }) {
        return {
            visitor: {
                ImportDeclaration(path, source) {
                    const { opts: { libraryName, alias } } = source
                    if(! t.isStringLiteral(path.node.source, {value: libraryName })) {
                        return
                    }
                    const newImports = path.node.specifiers.map(item= > {
                        const str = toLine(item.local.name)
    
                        return t.importDeclaration(
                            [t.importDefaultSpecifier(item.local)],
                            t.stringLiteral(`${alias}/${str}`)
                        )
                    })
    
                    path.replaceWithMultiple(newImports)
                }
            }
        }
    }
    Copy the code
    • .babelrcUsing our plugin,babel-loaderOur customization will be performed at compile timejs
    • Configure our custom package namesrc-components(Used when quoting)
    • Configure the path for the components we need to loadalias
    • Mapping rule conversion: capital hump – dash naming
    • The final path is:alias + name
    • Congratulations, you’re done here

3. Hands-on experience

Modify the introduction of components, save, compile normal, without any problems; Try building again. No problem at all.

Review and reflection

This approach really brings us great convenience, optimizing a lot of code and making it simple and easy to read. In this case, our code is comparable to antD writing.

Wait, how does ANTD implement on-demand import? Babel-plugin-import is used, so let’s see. Babelrc:

// .babelrc
[
    "import",
    {
        "libraryName": "antd"."libraryDirectory": "es"."style": true}]Copy the code

Wokaka, isn’t it surprisingly similar? It’s just that someone else has done something extra to introduce the CSS to the package.

At this point, to the end of the text. From discovering problems to solving them, from writing plug-ins to discovering principles on demand, we’ve learned more than a little!