1

需求:

客户的项目需要用我们的功能,且需要提供个modal嵌入到他们的项目里,在他们的table中点击对应的item,弹出我提供的modal。

解决方案

项目使用cra构建,使用webpack@5.70.0的library导出为一个库给第三方使用, 官方教程创建 library

   output: {
      library: 'Geek'
    }

这样的话客户就可以直接window.Geek.showModal()调用我们的弹窗
index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

import './index.css';
import 'antd/dist/antd.less';

import { defaultAuditRecord } from 'constants/configration';

const modalState = {};

const createContainer = () => {
  const container = document.createElement('div');
  container.setAttribute('id', 'container');
  document.body.append(container);
};

const renderApp = (showBtn) => {
  ReactDOM.render(
    <React.StrictMode>
      <App modalState={modalState} showBtn={showBtn} />
    </React.StrictMode>,
    document.getElementById('container')
  );
};
// 渲染sdk
export const mount = (showBtn) => {
  createContainer();
  renderApp(showBtn);
};
// 显示弹窗
export const showModal = (record = defaultAuditRecord, callback = () => {}) => {
  // record 为{id:1,user:""}
  modalState.showModal(record, callback);
};

export const closeModal = () => {
  modalState.closeModal();
};

// mount(true);

客户调用sdk

  const handleAuditBtnClick = useCallback(
    (record) => () => {
      window.Geek.showModal(
        { id: record.id, user: record.username },
        (event) => { // sdk的modal操作动作执行后的回调
          if (
            event === AuditModalEvent.SAVE_SUCCESS ||
            event === AuditModalEvent.SUBMIT_SUCCESS ||
            event === AuditModalEvent.CANCEL_SUCCESS
          ) {
            fetchList();
          }
        }
      );
    },
    [fetchList]
  );

  useEffect(() => {
    window.Geek.mount();
  }, []);

为了方便将sdk发给客户,将MiniCssExtractPlugin从配置中移除。

遇到的坑

  1. 自定义样式冲突
    sdk项目使用的是styled-components,我们内部测试sdk的项目也是用styled-components创建的,我本以为该库生成的classname是随机的,但是两个项目生成的classname很多都是重复的,崩溃。。。 最容易想到的是为sdk所有classname加个前缀。
    package.json

    "babel": {
     "presets": [
       "@babel/preset-env"
     ],
     "plugins": [
       [
         "babel-plugin-styled-components",
         {
           "namespace": "geek-sdk"
         }
       ]
     ]
    },
  2. antd的样式跟客户的样式冲突
    客户的项目也用到了antd,只不过是vue版的,但是有些样式是一样的。解决思路同样是修改控件的前缀。
    App.js

    import { ConfigProvider, message } from 'antd';
    
    message.config({
      prefixCls: 'sdk-antd-message',
    });
    
     <ConfigProvider locale={zhCN} prefixCls={'sdk-antd'}>
       {showBtn && (
         <div className="App">
           <header className="App-header">
             <p>
               Edit <code>src/App.js</code> and save to reload.
             </p>
           </header>
           <button onClick={show}>点击</button>
         </div>
       )}
       <Modal modalState={modalState}></Modal>
     </ConfigProvider>

index.js

import 'antd/dist/antd.less';

webpack.config.js

{
              test: /\.less$/,
              use: [
                {
                  loader: 'style-loader',
                },
                {
                  loader: 'css-loader', 
                },
                {
                  loader: 'less-loader', 
                  options: {
                    lessOptions: {
                      modifyVars: {
                        '@ant-prefix': 'sdk-antd',
                      },
                      javascriptEnabled: true,
                    },
                  },
                },
              ],
            },

修改后的样式

image.png

  1. sdk 在客户的项目中编译报错 unexpected token
    客户的项目是vue3的环境,将sdk放在src目录下编译就会报错,那么只好绕过编译,将生成的sdk.js 放到public目录下,在index.html用script标签直接引用,这样就不会报错了。

assassin_cike
1.3k 声望74 粉丝

生活不是得过且过