## deep-import-loader

### 介绍

利用webpack构建代码时，通过分析依赖关系，寻找到所有的import的最终指向并进行替换，以避免项目在打包时将某个npm包完整引入，以此来减少无用模块，降低代码体积。

![https://c-zhuo.github.io/easycanvas/](https://raw.githubusercontent.com/c-zhuo/deep-import-loader/master/example.png)

### 与webpack的tree-shaking的区别

虽然webpack也提供了类似的按需引入模块的功能，但触发条件比较苛刻。例如，如果项目将代码编译为commonjs（很多项目使用了@babel/plugin-transform-modules-commonjs或babel-plugin-transform-es2015-modules-commonjs），那么按模块的导出将失效。或者，一些组件库、工具集的npm包并没有在package.json中声明sideEffects，即使我们可以确定它不含副作用，也无法按模块引入。一些做法是引入具体路径，例如`import Foo from 'somemodule/lib/foo'`，但是开发不友好、容易疏漏，并且需要了解模块的目录结构。

### 原理

在其它loader之前编译代码，对所有`import ... from ...`语句进行分析。如果发现某一个模块来自更深层级的文件，那么会将路径指向该文件再进行打包。例如：

```
// Before
import { Foo, Bar } from 'module1';
import { Foo as myFoo } from 'module2';`

// After
// 例如 Foo 来自于 foo.js 的默认导出
import Foo from 'module/path/foo.js';
// 例如 Bar 来自于 utils.js 的 export { Bar }
import { Bar } from 'module/path2/utils.js';`
// 兼容 as 和 tsx 等用法和语法
import myFoo from 'module/path3/foo.tsx';`
```

### 如何使用

1. 安装deep-import-loader：

	`npm install deep-import-loader` 或 `yarn add deep-import-loader`

2. 修改webpack配置，在rules的末尾增加此项（以webpack@4为例）：

    ```
    rules: [{
        test: /\.(js|jsx|ts|tsx)$/,
        use: [
            // ... other rules
            {
                loader: 'deep-import-loader',
                options: {
                    blackList: ['adirtymodule'],
                    whiteList: ['somemodule', 'anothermodule'],
                    log: true,
                    warn: true
                }
            }
        ]
    }]
    ```

    在末尾增加的原因是rules是倒序执行的，以此确保deep-import-loader会先拿到代码，进行转换后再输出给其它loader，避免其它loader预先将import编译为其它写法。

    参数介绍：

    | Props | Default | Description |
    |---------|--------|-------------|
    | blackList | [] | npm包黑名单，引用这些包中的模块时会跳过替换。 |
    | whiteList | [] | npm包白名单，在白名单中的包才一定会进行import指向的替换。否则会根据这个包在package.json中的设置，当sideEffects为false时才会替换。设置为星号'*'代表全部替换。 |
    | log | false | 打包时，显示出有哪些模块被调整了引入路径、新路径。 |
    | warn | false | 打包时，显示出有哪些模块调整时没有找到真正的路径，保持原样。 |

3. 如果项目中的文件类型为vue，需要在plugins中引入VueLoaderPlugin。注意不要修改上面的test。参考[https://vue-loader.vuejs.org/guide/#webpack-configuration](https://vue-loader.vuejs.org/guide/#webpack-configuration)。
