Это вторая часть создания библиотеки компонентов с использованием vue3 и накопительного пакета. мы будем создавать сводную конфигурацию, чтобы мы могли собрать нашу библиотеку.

Давайте установим несколько необходимых нам библиотек.
yarn add @babel/[email protected] @rollup/[email protected] @rollup/[email protected] @rollup/[email protected] @rollup/[email protected] @rollup/[email protected] @rollup/[email protected] @rollup/[email protected]
[email protected] [email protected] [email protected] [email protected] [email protected] [email protected]

давайте обновим наш babel.config.js

module.exports = {
  presets: [
    "@babel/preset-env"
  ]
}

rollup-plugin-vue будет использоваться для обработки шаблонов vue и rollup-plugin-postcss с обработкой нашего postcss.

Теперь, когда у нас есть все зависимости, мы можем написать нашу конфигурацию. Давайте создадим rollup.config.js, сначала мы создадим baseconfig, который можно будет повторно использовать для различных сборок модульной системы.

Давайте импортируем все необходимые нам зависимости

import fs from 'fs';
import path from 'path';
import vue from 'rollup-plugin-vue';
import alias from '@rollup/plugin-alias';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import replace from '@rollup/plugin-replace';
import babel from '@rollup/plugin-babel';
import PostCSS from 'rollup-plugin-postcss';
import simplevars from 'postcss-simple-vars'
import postcssImport from 'postcss-import'
import minimist from 'minimist';
import postcssUrl from 'postcss-url'
import url from '@rollup/plugin-url'
import nested from 'postcss-nested'
import { terser } from 'rollup-plugin-terser'
import  autoprefixer  from 'autoprefixer

давайте добавим переменную, которую мы можем использовать, чтобы определить, какой модуль мы собираемся построить, и корневой путь нашего проекта:

const argv = minimist(process.argv.slice(2));
const projectRoot = path.resolve(__dirname, '.');

мы добавим такой скрипт в package.json
"build:es": "rimraf dist && cross-env NODE_ENV=production rollup --config rollup.config.js --format es"

Давайте теперь создадим baseConfig, конфигурация baseconfig будет привязана к vue, он будет иметь дело с preVue, Vue, postVue и babelConfig.

const baseConfig = {
  plugins: {
    preVue: [
      alias({
        entries: [
          {
            find: '@',
            replacement: `${path.resolve(projectRoot, 'src')}`,
          },
        ],
        customResolver: resolve({
          extensions: ['.js', '.jsx', '.vue'],
        }),
      }),
    ],
    replace: {
      'process.env.NODE_ENV': JSON.stringify('production'),
      __VUE_OPTIONS_API__: JSON.stringify(true),
      __VUE_PROD_DEVTOOLS__: JSON.stringify(false),
    },
    vue: {
      target: 'browser',
      preprocessStyles: true,
      postcssPlugins:[
       ...postcssConfigList
      ]
    },
    postVue: [
      // Process only `<style module>` blocks.
      PostCSS({
        modules: {
          generateScopedName: '[local]___[hash:base64:5]',
        },
        include: /&module=.*\.css$/,
      }),
      // Process all `<style>` blocks except `<style module>`.
      PostCSS({ include: /(?<!&module=.*)\.css$/,
        plugins:[
          ...postcssConfigList
        ]
       }),
        url({
          include: [
            '**/*.svg',
            '**/*.png',
            '**/*.gif',
            '**/*.jpg',
            '**/*.jpeg'
          ]
        }),
    ],
    babel: {
      exclude: 'node_modules/**',
      extensions: ['.js', '.jsx', '.vue'],
      babelHelpers: 'bundled',
    },
  },
};

Вышеупомянутый конфиг будет использоваться для разных сборок, у нас также есть postconfig, который используется в разных местах.

baseConfig.vue - это часть, которая используется rollup-plugin-vue для компиляции нашей кодовой базы, а затем различные плагины действуют соответствующим образом.

Прежде чем мы продолжим, мы объявим некоторые глобальные и внешние объекты, которые используются объединением для определения внешних зависимостей и глобальных выходов.
const external = ['vue'];
const globals = { vue: 'Vue' };

Давайте создадим точки входа для наших проектов, там будет одна точка входа по умолчанию как src / index.js и разная для каждого компонента index.js, например, components / helloworld / index.js

const baseFolder = './src/'
const componentsFolder = 'components/'

const components = fs
  .readdirSync(baseFolder + componentsFolder)
  .filter((f) =>
    fs.statSync(path.join(baseFolder + componentsFolder, f)).isDirectory()
  )

const entriespath = {
  index: './src/index.js',
  ...components.reduce((obj, name) => {
    obj[name] = (baseFolder + componentsFolder + name + '/index.js')
    return obj
  }, {})
}

const capitalize = (s) => {
  if (typeof s !== 'string') return ''
  return s.charAt(0).toUpperCase() + s.slice(1)
}

Теперь, когда точки входа готовы, давайте напишем суть сборщиков модулей. Мы будем использовать вышеупомянутый argv, чтобы определить, какую сборку модуля мы должны построить.

Начнем с сборки esm

(argv === ‘es’)
конфигурация будет следующей:

// Customize configs for individual targets
let buildFormats = [];
// this will hold our whole configuration object 

if (!argv.format || argv.format === 'es') {
  const esConfig = {
    input: entriespath,
    external,
    output: {
        format: 'esm',
        dir: 'dist/esm'
    },
    plugins: [
      commonjs(),
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      babel({
        ...baseConfig.plugins.babel,
        presets: [
          [
            '@babel/preset-env',
            { modules: false }
          ],
        ],
      }),
    ],
  };

  const merged = {
    input: 'src/index.js',
    external,
    output: {
      format: 'esm',
      file: 'dist/vuelib.esm.js'
    },
    plugins: [
      commonjs(),
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      babel({
        ...baseConfig.plugins.babel,
        presets: [
          [
            '@babel/preset-env',
            { modules: false }
          ],
        ],
      }),
    ]
  }
  buildFormats.push(esConfig);
  buildFormats.push(merged);
}

Это устанавливает нашу конфигурацию для сборок esm. Сборщики модулей (rollup, webpack) выбирают эти сборки.

Таким образом, у нас есть единственная сборка, в которой весь наш код, а остальные - это части из esm / index.js.

Также с этим у нас может быть treehaking в проекте, который использует библиотеку.

с обоими компонентами

Это только с одним компонентом.

В сборку входит только тот компонент, который входит в комплект.

Теперь давайте добавим другие конфигурации модуля:

if (!argv.format || argv.format === 'iife') {
  const unpkgConfig = {
    ...baseConfig,
    input: './src/index.js',
    external,
    output: {
      compact: true,
      file: 'dist/vuelib-browser.min.js',
      format: 'iife',
      name: 'vuelib',
      exports: 'named',
      globals,
    },
    plugins: [
      commonjs(),
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue(baseConfig.plugins.vue),
      ...baseConfig.plugins.postVue,
      babel(baseConfig.plugins.babel),
      terser({
        output: {
          ecma: 5,
        },
      }),
    ],
  };
  buildFormats.push(unpkgConfig);
}

if (!argv.format || argv.format === 'cjs') {
  const cjsConfig = {
    ...baseConfig,
    input: entriespath,
    external,
    output: {
      compact: true,
      format: 'cjs',
      dir: 'dist/cjs',
      exports: 'named',
      globals,
    },
    plugins: [
      commonjs(),
      replace(baseConfig.plugins.replace),
      ...baseConfig.plugins.preVue,
      vue({
        ...baseConfig.plugins.vue,
        template: {
          ...baseConfig.plugins.vue.template,
          optimizeSSR: true,
        },
      }),
      ...baseConfig.plugins.postVue,
      babel(baseConfig.plugins.babel),
    ],
  };
  buildFormats.push(cjsConfig);
}

Давайте создадим индивидуальную сборку для каждого компонента, т.е. umd Builds

const mapComponent = (name) => {
    return [
      {
        input: baseFolder + componentsFolder + `${name}/index.js`,
        external,
        output: {
          format: 'umd',
          name: capitalize(name),
          file: `dist/components/${name}/index.js`,
          exports: 'named',
          globals,
        },
        plugins: [
          ...baseConfig.plugins.preVue,
          vue({}),
          ...baseConfig.plugins.postVue,
          babel({
            ...baseConfig.plugins.babel,
            presets: [
              [
                '@babel/preset-env',
                { modules: false }
              ],
            ],
          }),
          commonjs(),
        ]
      }
    ]
  }

const ind = [...components.map((f) => mapComponent(f)).reduce((r, a) => r.concat(a), [])]

buildFormats = [...buildFormats, ...ind]

Теперь, когда все форматы сборки готовы, мы можем экспортировать всю нашу конфигурацию

export default buildFormats;

Давайте внесем изменения в наш package.json

...
"main": "dist/cjs/index.js",
  "module": "dist/esm/index.js",
  "unpkg": "dist/vuelib.min.js",
  "files": [
    "dist",
    "src"
  ],
  "sideEffects": [
    "*.css",
    "*.scss"
  ],
 "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "build:es": "rimraf dist && cross-env NODE_ENV=production rollup --config rollup.config.js --format es",
    "build:js": "rimraf dist && cross-env NODE_ENV=production rollup --config rollup.config.js"
  },

...

при этом каждый проект будет правильно подбирать нужные им форматы. Проекты commonjs выбирают папку cjs, а проекты webpack или rollup - папку pic esm.

С этой конфигурацией мы можем построить нашу библиотеку. Мы добавили в нашу библиотеку препроцессоры treehaking и postcss.

Примечание: мы встроили CSS непосредственно в компоненты на тот случай, если нам понадобится CSS в разных файлах, например, в bundle.css, нам нужно использовать плагины, такие как rollup-plugin-scss, rollup-plugin-css-only.

Итак, мы создали библиотеку компонентов vue 3 с rollup и postcss, и у нее есть возможность сотрясения деревьев.

Код, относящийся к этой статье, доступен на Github.