Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第 9 题: 简单实现项目代码按需加载,例如import { Button } from 'antd',打包的时候只打包button #9

Open
airuikun opened this issue Apr 8, 2019 · 5 comments

Comments

@airuikun
Copy link
Owner

@airuikun airuikun commented Apr 8, 2019

原理很简单,就是将

import { Select, Pagination, Button } from 'xxx-ui';

通过babel转化成

import Button from `xxx-ui/src/components/ui-base/Button/Button`;
import Pagination from `xxx-ui/src/components/ui-base/Pagination/Pagination`;
import Select from `xxx-ui/src/components/ui-base/Select/Select`;

自定义拓展一个babel插件,代码如下:

visitor: {
	ImportDeclaration (path, { opts }) {
	    const specifiers = path.node.specifiers;
	    const source = path.node.source;

            // 判断传入的配置参数是否是数组形式
	    if (Array.isArray(opts)) {
	        opts.forEach(opt => {
	            assert(opt.libraryName, 'libraryName should be provided');
	        });
	        if (!opts.find(opt => opt.libraryName === source.value)) return;
	    } else {
	        assert(opts.libraryName, 'libraryName should be provided');
	        if (opts.libraryName !== source.value) return;
	    }

	    const opt = Array.isArray(opts) ? opts.find(opt => opt.libraryName === source.value) : opts;
	    opt.camel2UnderlineComponentName = typeof opt.camel2UnderlineComponentName === 'undefined'
	        ? false
	        : opt.camel2UnderlineComponentName;
	    opt.camel2DashComponentName = typeof opt.camel2DashComponentName === 'undefined'
	        ? false
	        : opt.camel2DashComponentName;

	    if (!types.isImportDefaultSpecifier(specifiers[0]) && !types.isImportNamespaceSpecifier(specifiers[0])) {
	        // 遍历specifiers生成转换后的ImportDeclaration节点数组
    		const declarations = specifiers.map((specifier) => {
	            // 转换组件名称
                    const transformedSourceName = opt.camel2UnderlineComponentName
                	? camel2Underline(specifier.imported.name)
                	: opt.camel2DashComponentName
            		    ? camel2Dash(specifier.imported.name)
            		    : specifier.imported.name;
    		    // 利用自定义的customSourceFunc生成绝对路径,然后创建新的ImportDeclaration节点
                    return types.ImportDeclaration([types.ImportDefaultSpecifier(specifier.local)],
                	types.StringLiteral(opt.customSourceFunc(transformedSourceName)));
                });
                // 将当前节点替换成新建的ImportDeclaration节点组
    		path.replaceWithMultiple(declarations);
    	}
    }
}
@David-Tsui

This comment has been minimized.

Copy link

@David-Tsui David-Tsui commented Apr 11, 2019

請問何時會需要如此功能呢?(搔頭

@chengqilong

This comment has been minimized.

Copy link

@chengqilong chengqilong commented Apr 15, 2019

請問何時會需要如此功能呢?(搔頭

看来你还不知道按需使用antd,或者其他第三方的库,这是减少包体积的常见问题呀

@David-Tsui

This comment has been minimized.

Copy link

@David-Tsui David-Tsui commented Apr 15, 2019

請問何時會需要如此功能呢?(搔頭

看来你还不知道按需使用antd,或者其他第三方的库,这是减少包体积的常见问题呀

喔 現在看懂了,原本以為是要延伸或是縮小第三方庫單一組件代碼。
應該是當時眼花了哈哈

@airuikun

This comment has been minimized.

Copy link
Owner Author

@airuikun airuikun commented Apr 15, 2019

請問何時會需要如此功能呢?(搔頭

看来你还不知道按需使用antd,或者其他第三方的库,这是减少包体积的常见问题呀

喔 現在看懂了,原本以為是要延伸或是縮小第三方庫組件代碼。
應該是當時眼花了哈哈

嗯 现在webpack的tree shaking 和antd自带的一个plugin也有按需加载 这题就考一下按需加载的实现原理 当然 我的答案是通过编写babel插件去实现按需加载 你要是有别的方法 也可以共享出来

@xinbbbb

This comment has been minimized.

Copy link

@xinbbbb xinbbbb commented Oct 9, 2019

webpack4 + babel7 已经可以实现tree shaking了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.