最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 用 RollupJs 从 0 搭建一个属于自己的 vue 组件库

    正文概述 掘金(对半)   2021-05-15   1147

    前言

    现在前端的打包工具主要有 webpackrollupgulp等。

    Gulp 是一个基于任务驱动的自动化构建工具。

    Webpack 是当下最热门的前端资源模块化 管理和打包工具。它可以将许多松散的模块按照依赖和规则打包成符合生产环境部署的前端资源。还可以将按需加载的模块进行代码分割,等到实际需要的时候再异步加载。

    Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。

    Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD。ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码。ES6 模块最终还是要由浏览器原生实现,但当前 Rollup 可以使你提前体验。

    简单点来说,就是 gulp 适合小项目,基于流程构建;webpack 适用于大型的应用项目,以模块划分,按需加载;而 rollup 适用于工具库的构建,优化代码。现在前端的 vue、 react 框架都是用 rollup 来打包的,也有一些 ui 框架的打包也是用的 rollup。

    本文思路参考了 Element3 的构建,以 vue3 + rollup + ts + gulp 结合

    初始化工作

    用 npm init 初始化一个项目,然后安装一些必要的 npm 包:

    // 初始化
    npm init
    
    // 安装必要的 rollup 的 npm 包
    yarn add -D
        rollup-plugin-vue                // 类似于 webpack 的vue-loader,vue 组件的加载器
        rollup-plugin-scss               // scss 解析插件
        rollup-plugin-peer-deps-external // 打包的时候用来排除 package.json 内 peerDependencies 字段内的包
        @rollup/plugin-node-resolve      // 使用Node解析算法定位模块
        @rollup/plugin-commonjs          // CommonJS模块转换
        @rollup/plugin-json              // json 文件解析
        @rollup/plugin-replace           // 在打包文件时替换文件中的字符串
        @rollup/plugin-babel             // 转译 JavaScript 新特性
        rollup-plugin-typescript2        // 用于解析ts文件,并生成 x.d.ts 类型文件
        rollup-plugin-terser             // 包最小化生成,也就是压缩
        
    // 还需要安装 @vue/compiler-sfc @babel/core typescript rollup 
        
    // package.json
    {
      "peerDependencies": { // 打包将排除vue
        "vue": "^3.0.11"
      }
    }
    

    在根目录新建 tsconfig.json

    {
      "compilerOptions": {
        "target": "esnext",
        "module": "esnext",
        "jsx": "preserve",
        "declaration": true,
        "importHelpers": true,
        "moduleResolution": "node",
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,
        "baseUrl": ".",
        "allowJs": true,
        "lib": ["esnext", "dom", "dom.iterable", "scripthost"],
        "outDir": "./",
        "resolveJsonModule": true
      },
      "include": ["src", "packages"],
      "exclude": ["node_modules"]
    }
    

    rollup.config.js

    然后再在根目录新建 rollup.config.js

    // 引入 rollup 相关的包
    import pkg from './package.json'
    import vuePlugin from 'rollup-plugin-vue'
    import scss from 'rollup-plugin-scss'
    import peerDepsExternal from 'rollup-plugin-peer-deps-external'
    import resolve from '@rollup/plugin-node-resolve'
    import commonjs from '@rollup/plugin-commonjs'
    import json from '@rollup/plugin-json'
    import replace from '@rollup/plugin-replace'
    import babel from '@rollup/plugin-babel'
    import ts from 'rollup-plugin-typescript2'
    import { terser } from 'rollup-plugin-terser'
    
    // 先定义一个 base 配置
    // 创建打包文件的头部信息
    const createBanner = () => {
      return `/*!
      * ${pkg.name} v${pkg.version}
      * (c) ${new Date().getFullYear()} test
      * @license ISC
      */`
    }
    
    // 创建基础配置
    const createBaseConfig = () => {
      return {
        input: 'src/index.ts', // 加载入口
        external: ['vue'],
        plugins: [ // 插件加载
          peerDepsExternal(),
          vuePlugin({
            css: true
          }),
          ts(),
          babel({
            exclude: 'node_modules/**',
            extensions: ['.js', '.jsx', '.vue'],
            babelHelpers: 'bundled'
          }),
          resolve({
            extensions: ['.vue', '.jsx', '.js']
          }),
          commonjs(),
          json(),
          scss()
        ],
        output: {
          sourcemap: false,
          banner: createBanner(),
          externalLiveBindings: false,
          globals: {
            vue: 'Vue'
          }
        }
      }
    }
    

    然后定义不同格式的输出及其它配置:

    // 生成文件名
    function createFileName(formatName) {
      return `dist/taxreview.${formatName}.js`
    }
    
    // es-bundle
    const esBundleConfig = {
      plugins: [
        replace({
          preventAssignment: true,
          __DEV__: `(process.env.NODE_ENV !== 'production')`
        })
      ],
      output: {
        file: createFileName('esm-bundler'),
        format: 'es'
      }
    }
    
    // cjs
    const cjsConfig = {
      plugins: [
        replace({
          preventAssignment: true,
          __DEV__: true
        })
      ],
      output: {
        file: createFileName('cjs'),
        format: 'cjs'
      }
    }
    // cjs.prod
    const cjsProdConfig = {
      plugins: [
        terser(),
        replace({
          preventAssignment: true,
          __DEV__: false
        })
      ],
      output: {
        file: createFileName('cjs.prod'),
        format: 'cjs'
      }
    }
    // 其它的格式还有 es-browser global 等
    

    对于不同的环境打不同的包

    // 生产
    const prodFormatConfigs = [
      esBundleConfig,
      cjsConfig,
      cjsProdConfig
    ]
    const devFormatConfigs = [esBundleConfig] // 开发
    

    最后执行打包程序

    function mergeConfig(baseConfig, configB) {
      const config = Object.assign({}, baseConfig)
      // plugin
      if (configB.plugins) {
        baseConfig.plugins.push(...configB.plugins)
      }
    
      // output
      config.output = Object.assign({}, baseConfig.output, configB.output)
    
      return config
    }
    function createPackageConfigs() {
      return getFormatConfigs().map((formatConfig) => {
        return mergeConfig(createBaseConfig(), formatConfig)
      })
    }
    
    function getFormatConfigs() {
      return process.env.NODE_ENV === 'development'
        ? devFormatConfigs
        : prodFormatConfigs
    }
    
    export default createPackageConfigs()
    

    vue 组件的处理

    在根目录新建一个 packages 文件夹用来存放所有组件,在 packages 内部新建一个 theme-chalk 文件夹用来存放 scss 文件,不要在 vue 文件内直接写 scss,之后 theme-chalk 内的 scss 文件用 gulp 来打包。

    // packages/Test/src/Test.vue
    <template>
      <div>
        {{msg}}
      </div>
    </template>
    
    <script lang="ts">
    import { defineComponent, ref } from 'vue'
    
    export default defineComponent({
      name: 'test',
      setup() {
        let msg = ref('test')
    
        return { msg }
      }
    })
    </script>
    
    // packages/Test/index.ts
    import Test from './src/Test.vue'
    
    /* istanbul ignore next */
    Test.install = function (app) {
      app.component(Test.name, Test)
    }
    
    export { Test }
    

    然后在根目录下 src/index.ts 执行整个程序的启动

    // src/index.ts
    import { Test } from '../packages/Test'
    
    import { version } from '../package.json'
    import { setupGlobalOptions } from './globalConfig' // 这个文件用来设置这个ui库的一些全局属性
    
    const components = [
      Test
    ]
    
    // 这个是用 vue.use 用来注册全局组件的
    const install = (app, opts = {}) => {
      app.use(setupGlobalOptions(opts))
    
      components.forEach((component) => {
        app.use(component)
      })
    
      applyOptions(app)
    }
    
    // 这个是用来挂载像 Message 这样用 js 来调用的组件
    function applyOptions(app) {
      app.config.globalProperties.$test = Test
    }
    
    const taxreview = {
      version,
      install
    }
    
    // 这个是用来单独引用的
    export {
      Test,
      install
    }
    
    export default taxreview
    
    // src/globalConfig.ts  用来设置ui库的一些全局属性
    import { getCurrentInstance } from 'vue'
    
    /**
     * get globalOptions $TAXREVIEW config object
     */
    export function useGlobalOptions() {
      const instance = getCurrentInstance()
    
      if (!instance) {
        console.warn('useGlobalOptions must be call in setup function')
        return
      }
    
      return instance.appContext.config.globalProperties.$TAXREVIEW || {}
    }
    
    export function setupGlobalOptions(opts: any = {}) {
      return (app) => {
        app.config.globalProperties.$TAXREVIEW = {
          size: opts.size || '',
          zIndex: opts.zIndex || 2000
        }
      }
    }
    

    我们还需要修改下 package.json

    {
      "main": "dist/taxreview.cjs.js", // 引入包的主入口文件
      "types": "dist/src/index.d.ts", // 指定类型声明文件
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "rollup -c" // 启动打包
      }
      // 其它配置
    }
    

    到这里用 yarn build 就可以打包 vue 组件了

    用 RollupJs 从 0 搭建一个属于自己的 vue 组件库

    css 处理

    我们的全部 css 都放入了 packages/theme-chalk/src 下面,所以我们可以在 packages/theme-chalk 构建 gulp 打包

    // packages/theme-chalk/gulpfile.js
    'use strict'
    
    const { series, src, dest } = require('gulp')
    const sass = require('gulp-sass')
    const autoprefixer = require('gulp-autoprefixer')
    const cssmin = require('gulp-cssmin')
    
    // 将 scss 文件转译成 css 文件并压缩放入同级的 lib 文件夹内
    function compile() {
      return src('./src/*.scss')
        .pipe(sass.sync())
        .pipe(
          autoprefixer({
            overrideBrowserslist: ['ie > 9', 'last 2 versions'],
            cascade: false
          })
        )
        .pipe(cssmin())
        .pipe(dest('./lib'))
    }
    
    // 用来拷贝字体文件
    function copyfont() {
      return src('./src/fonts/**').pipe(cssmin()).pipe(dest('./lib/fonts'))
    }
    
    exports.build = series(compile, copyfont)
    

    然后在根目录的 package.json 再添加一个处理 scss 的命令

    // cp-cli A B: 命令是将路径 A 的文件全部拷贝到路径 B
    {
      "build:theme": "node scripts/generateCssFile.js && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk"
    }
    
    // yarn build:theme
    

    最后

    最后我们将包用 npm publish 发布到npm,然后就可以用 yarn add xxx 来应用于项目了。

    GitHub: github.com/554246839/r… master 分支


    起源地下载网 » 用 RollupJs 从 0 搭建一个属于自己的 vue 组件库

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元