组件打包umd格式发布npm

943 阅读3分钟

简介:

本文讲述一个原生JS组件打包成UMD模块发布到npm依赖的过程。

原生JS组件的好处是可以跨框架在多场景使用。

在打包成umd后可以直接当作sdk上传到cdn直接引用,这样的好处是当组件迭代时,只用更新cdn文件,清除缓存就可以升级版本,不用每个组件宿主去操作迭代

上传npm包方便版本的管理,受众更广,也可以回退到老版本。

组件背景:

一个原生定制化轮播图的广告banner

诉求:支持类swiper功能、支持配置、支持埋点、支持跳转、支持判断用户uid登录状态、支持不同省份类型

研发场景:支持原生html使用、支持vue2、vue3、react下使用

为了封装一个共用统一的组件,所以使用原生js创建一个轮播对象,使用fetch包装请求不依赖axios,这样组件就完全没有依赖,比较简洁。


umd格式

一、简介:
((root, factory) => {
  if (typeof define === 'function' && define.amd) {
    //AMD
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    //CommonJS
    var $ = requie('jquery');
    module.exports = factory($);
  } else {
    root.testModule = factory(root.jQuery);
  }
})(this, ($) => {
  //todo
});

可以看出它在定义模块的时候回检测当前使用环境和模块的定义方式,将各种模块化定义方式转化为同样一种写法。它没有自己专有的规范,是集结了 CommonJs、CMD、AMD 的规范于一身。

目前感觉打包成umd模式在外部引用比较方便,对于类库的打包我这里选择的工具是rollup。

npm install rollup --global
二、使用:

首先安装rollup

    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-eslint": "^7.0.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-cleanup": "^3.2.1",
    "rollup-plugin-terser": "^7.0.2"

devDependencies中使用到的工具需要安装

import babel from "rollup-plugin-babel";
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from "rollup-plugin-replace";
import { terser } from 'rollup-plugin-terser';
import cleanup from 'rollup-plugin-cleanup';
// rollup.config.js
export default {
    input: "./new.js",//入口
    output: [
        {
            file: "dist/banner.esm.js",
            format: "es",
            name: 'xinghuobanner'
        },
        {
            file: "dist/banner.umd.js",
            format: "umd",
            name: 'xinghuobanner'
        },
        {
            file: "dist/banner.js",
            format: "commonjs",
            name: 'xinghuobanner'
        },
    ],//输出
    plugins: [
        replace({
            ENV: JSON.stringify(process.env.NODE_ENV)
        }),//替换环境变量
        resolve({
            jsnext: true,
            main: true,
            browser: true,
        }), //处理导入语句
        commonjs(),//转换commonjs
        terser(),//压缩插件
        cleanup(),//清除无用代码
        babel({
            exclude: 'node_modules/**',
        }),//babel转换ES6语法
    ],
};

写好最基础的rollup配置,输出esm、umd、cmjs的格式,

配置npm run build:rollup --config rollup.config.js

最终输出dist目录

html中引入index.js文件 js直接使用dist下的文件就可以使用了,因为是import引入所以使用esm的es6版本

dist目录中的banner.umd.js直接上传到cdn上就可以直接使用了。

发布npm

步骤一、package.json配置

设置package.json中的配置项

{
  "name": "nohx-banner",
  "version": "0.0.7",
  "private": false,
  "main":"dist/banner.umd.js",
  "author": {
    "name": "chenxinxin",
    "github":"https://github.com/cxx3668119/xh-banner"
  },
  "scripts": {
    "start": "rollup",
    "build": "rollup --config rollup.config.js"
  },
  "devDependencies": {
    "@babel/core": "^7.20.12",
    "@babel/preset-env": "^7.20.2",
    "eslint": "^8.33.0",
    "rollup": "^2.79.1",
    "rollup-plugin-babel": "^4.4.0",
    "rollup-plugin-commonjs": "^10.1.0",
    "rollup-plugin-eslint": "^7.0.0",
    "rollup-plugin-node-resolve": "^5.2.0",
    "rollup-plugin-replace": "^2.2.0",
    "rollup-plugin-cleanup": "^3.2.1",
    "rollup-plugin-terser": "^7.0.2"
  }
}

name必须是npm上没有的;

version命名规定版本号

private必须是false才能发布npm

main指定入口文件

步骤二、npmignore配置

创建一个npmignore文件

npmignore 和 gitignore 和差不多

# 忽略目录
examples/
packages/
utils/
 
# 忽略指定文件
vue.config.js
babel.config.js
rollup.config.js
.eslintrc.js
index.js
new.js
.babelrc
*.map

这个文件的作用是将一些不需要上传到npm的路径、文件进行忽略,我们在上传时就不会上传这部分了

步骤三、上传npm

修改为npm原镜像

arduino
npm config set registry=https://registry.npmjs.org

添加npm用户

发布

在vue中体验

<template>
  <div class="banner"></div>
</template>

<script>
  const bannerList1 = [
    {
      ideaId: "ID297731547224522752_MA301786817089159168",
      ideaName: "banner",
      ideaStatus: "valid",
      ideaUrl: {
        originalLink: "http://www.baidu.com",
        viewUrl: "http://www.baidu.com",
        linkType: "H5_LINK"
      },
      ideaWords: [],
      isNotice: "0",
      nth: 1,
      picUrl: "https://ctopmweb-cdn.iyoudui.com/myx_draw/dxreq332/dxbg.png",
      sceneCode: "UN297726678627434496",
      sceneGroupCode: "DDPHHZLHETQS",
      spm: "a482.p1.m1.b1"
    },
    {
      ideaId: "ID297731547224522752_MA301786817089159168",
      ideaName: "banner",
      ideaStatus: "valid",
      ideaUrl: {
        originalLink: "http://www.baidu.com",
        viewUrl: "http://www.baidu.com",
        linkType: "H5_LINK"
      },
      ideaWords: [],
      isNotice: "0",
      nth: 1,
      picUrl: "https://csopmweb-cdn.iyoudui.com/busimamage/166719587403322.png",
      sceneCode: "UN297726678627434496",
      sceneGroupCode: "DDPHHZLHETQS",
      spm: "a482.p1.m1.b1"
    }
  ]
  import XinghuoBanner from 'nohx-banner/dist/banner.umd'
  export default {
    name: 'HelloWorld',
    props: {
      msg: String
    },
    mounted(){
      new XinghuoBanner('.banner', {
        bannerList: bannerList1,
        appId: "1123",
        uid: "2088612045761071",
        env: "test",
        projectType: "dx",
        channel: 'dx',
        // xhBannerZWM: '0JFMLVX2T4B5',
        mdValue: 'aST20230203175528871.p1.m6.b1',
        on: {
          xhclick: (e) => {
            console.log('banner clicked', e);
          }
        }
      })
    }
  }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

  .banner {
    width: 600px;
    height: 300px;
  }
</style>