technology-blog icon indicating copy to clipboard operation
technology-blog copied to clipboard

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

Open airuikun opened this issue 5 years ago • 6 comments

原理很简单,就是将

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);
    	}
    }
}

airuikun avatar Apr 08 '19 08:04 airuikun

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

David-Tsui avatar Apr 11 '19 06:04 David-Tsui

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

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

chengqilong avatar Apr 15 '19 07:04 chengqilong

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

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

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

David-Tsui avatar Apr 15 '19 07:04 David-Tsui

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

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

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

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

airuikun avatar Apr 15 '19 08:04 airuikun

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

xinbbbb avatar Oct 09 '19 08:10 xinbbbb

太苦了吧

haoolii avatar Aug 03 '20 06:08 haoolii