Упакуйте библиотеку компонентов vue по требованию от 0 до 1 с помощью веб-пакета

Webpack

При разработке проектов Vue мы будем абстрагировать часто используемую логику или модули в компоненты.Для тех компонентов, которые используются в нескольких проектах, мы можем рассмотреть возможность их инкапсуляции в библиотеки компонентов и публикации их в npm. нужно только каждый разnpm install xxОдин раз не нужно копировать туда-сюда. Давайте начнем с 0, чтобы упаковать библиотеку компонентов vue.

Общий способ использования библиотеки компонентов vue

  • 1. ПройтиscriptЗнакомство с этикеткой
<body>
    <div id="app">
        <hello></hello>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  <!--在组件库之前引入vue-->
<script src="../dist/my-lib.js"></script>
<script>
    new Vue({
        el: '#app'
    })
</script>
  • 2. Пройтиimportпредставлять
import Vue from "vue"
import App from "./App.vue"
import MyLib from "my-lib"
Vue.use(MyLib)
new Vue({
    name: "root",
    el: '#root',
    render: h => h(App)
})

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

<template>
  <div id="app">
      <hello></hello>
  </div>
</template>

Компоненты должны быть зарегистрированы, прежде чем они будут использоваться.Зарегистрированные компоненты могут быть зарегистрированы локально и глобально.Из использования библиотеки компонентов выше мы можем видеть, что компоненты библиотеки компонентов зарегистрированы глобально.

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

через второйimportПо пути введения проходимVue.use(MyLib)Завершите глобальную регистрацию компонентов.

Структура проекта библиотеки компонентов заключается в следующем.src/index.jsопределено вinstall方法.

//  src/index.js
import Hello from "./components/Hello.vue"

function install(Vue){   //外部的Vue.use(MyLib)会执行该方法,完成组件的全局注册。
  Vue.component(Hello.name, Hello)
}

if(window && window.Vue) {   //通过`script`标签引入的情况,在组件内部完成组件注册。
  Vue.use(install)
}

export default install

упаковка веб-пакета

Основное использование веб-пакета: webpack от мелкой до глубокой серии (1),Webpack от мелкой до глубокой серии (2)

Теперь наша библиотека компонентов всего однаhello组件, мы будем использовать webpack, чтобы упаковать его в библиотеку компонентов, которую можно использовать двумя указанными выше способами.Webpack упаковывает библиотеку компонентов vue, которая в основном аналогична упаковке обычного проекта vue. Толькоoutputизменяется, как показано ниже, добавляяlibraryTargetЖдать.

//webpack.config.js
const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
  mode: 'none',
  entry: './src/index.js',
  output: {
    path: path.join(__dirname,"/dist"),
    filename: 'my-lib.js',  
    libraryTarget: 'umd',  //用到的模块定义规范
    library: 'myLib',   //库的名字
    libraryExport: 'default'
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use:  ['vue-loader']
      },
      {
        test: /\.css$/,
        use:  ['style-loader','css-loader','postcss-loader']
      },
      {
          test: /\.s[ac]ss$/i,
          use:  ['style-loader','css-loader','postcss-loader','sass-loader']
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin()
  ]
}

libraryTarget

libraryTarget указывает спецификации определения модуля, используемые файлами упакованных библиотек, которые в основном включают следующее:var assign this window global jsonp commonjs commonjs2 amd umd. Ссылка на конкретное значениеофициальная документация

Здесь мы используемumd, он будет работать в среде CommonJS, AMD или экспортировать модуль в переменную под global. существуетumdОбщая структура файлов библиотек, экспортируемых в соответствии со спецификацией модуля, выглядит следующим образом, что мы часто видим в некоторых плагинах или файлах библиотек, таких как jquery.

//官方示例。 'MyLibrary'就是library中定义的库名称, 对应我们自己demo中的myLib。

(function webpackUniversalModuleDefinition(root, factory) {
  if(typeof exports === 'object' && typeof module === 'object')
    module.exports = factory();    
  else if(typeof define === 'function' && define.amd)
    define([], factory);           
  else if(typeof exports === 'object')
    exports['MyLibrary'] = factory();  
  else
    root['MyLibrary'] = factory();  
})(typeof self !== 'undefined' ? self : this, function() {
  return _entry_return_; // 此模块返回值,是入口 chunk 返回的值
});

написаноwebpack.config.js, вот такpackage.jsonСредняя конфигурацияscripts:

"scripts": {
   "build": "webpack"  //默认会执行根目录下的webpack.config.js
},

npm run build

Запакована нищенская версия библиотеки компонентов vue.

externals

В этой нашей библиотеке компонентов vue vue передается в качестве параметра. мы тожеimportдругие библиотеки. Когда функция этой библиотеки более сложна, это часто неизбежно.importДругие библиотеки, такие как статические методы, которые вы хотите использовать в Vue.Vue.xxxили библиотеку инструментов, например lodash.

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

Для этого требуется помощьexternals, что может предотвратить объединение некоторых импортированных пакетов в пакеты, а вместо этого получить эти внешне зависимые модули извне во время выполнения. надwebpack.config.jsдобавлено вexternals:

const path = require('path')
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
  ...
  externals : {
    vue: {
      root: "Vue",   //通过 script 标签引入,此时全局变量中可以访问的是 Vue
      commonjs: "vue",  //可以将vue作为一个 CommonJS 模块访问
      commonjs2: "vue",  //和上面的类似,但导出的是 module.exports.default
      amd: "vue"   //类似于 commonjs,但使用 AMD 模块系统
    }
  }
}

Конфигурация внешних переменных может принимать различные синтаксисы, такие как строка, массив, объект, функция и регулярное выражение.внешняя конфигурация

только тогда, когдаlibraryTarget: 'umd'Только когда объект, содержащий { root, amd, commonjs, ... }, может быть настроен, как указано выше, другие значения libraryTarget не могут быть настроены таким образом.

Чтобы протестировать конфигурацию экстерналов, мы запускаемsrc/index.jsДобавьте следующие две строки кода:

import Vue from "vue"
console.log(Vue)

Как отлаживать библиотеки компонентов локально

  • 1. Сначала отладимscriptВ случае введения тега создайте новый html-документ и импортируйте упакованную библиотеку компонентов.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <hello></hello>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="../dist/my-lib.js"></script>
<script>
    new Vue({
        el: '#app'
    })
</script>
</html>

  • 2,importвведена ситуация. Соберите vue-проект LibTest для тестирования или, что удобнее и быстрее, добавьте тестовый компонент в существующий vue-проект и добавьте его в роуты.

Измените основное поле в package.json проекта myLib., основное поле определяет входной файл пакета npm.

"main": "./dist/my-lib.js",

Выполнить в корневом каталоге проекта библиотеки компонентов myLib.npm link

cd myLib
npm link

Выполнить в корневом каталоге тестового проектаnpm link my-lib

cd LibTest
npm link my-lib  //这个my-lib是在myLib项目的package.json中定义的"name": "my-lib"

Затем его можно использовать как обычную установленную библиотеку компонентов npm.

В записи js тестового проекта LibTest импортируйтеmy-lib,воплощать в жизньVue.use()Регистрация компонентов

import MyLib from 'my-lib'
Vue.use(MyLib)

Используйте компонент в App.vue LibTest:

<template>
  <div>
    <hello></hello>
  </div>
</template>

нагрузка по требованию

Мы просмотрели базовую библиотеку компонентов, давайте превратим ее в библиотеку компонентов по требованию.

Для проектов библиотек компонентов необходимо обеспечить поддержку загрузки по запросу: библиотека компонентов экспортируется модульным способом es6. То есть файл экспорта должен быть экспортирован и импортирован следующим образом:

import { xxx } from 'xxx'
import yyy from yyy
export default zzz;
export { a, b, c };

Удалите неиспользуемый код с помощью Tree-Shaking.

Принцип Tree-Shaking, растрескивание стен рекомендуется внимательно прочитать эти две статьи:

Практика оптимизации производительности Tree-Shaking — принципы,Ваш Tree-Shaking бесполезен

1ES6的模块引入是静态分析的,故而可以在编译时正确判断到底加载了什么代码。
2、分析程序流,判断哪些变量未被使用、引用,进而删除此代码。

В базовой упаковке мы знаем, что webpack имеет несколько режимов экспорта (libraryTarget), но webpack не поддерживает режим экспорта модулей ES. Режим экспорта «umd», который обычно выбирают все, его экспортный файл также является функцией немедленного выполнения, которая вообще не соответствует модульному способу es6. В соответствии с приведенной выше конфигурацией нет возможности загрузки по требованию.

Существует множество библиотек, которые упаковывают каждый компонент или функцию в отдельный файл или каталог для справки по требованию. Затем укажите путь к файлу:

import 'echarts/lib/chart/pie'
import 'echarts/lib/component/title'

Этот способ написания не может вводить несколько компонентов одновременно, и он недостаточно элегантен. element-ui специально разработал плагин babelbabel-plugin-component, что позволяет нам импортировать по требованию следующим образом:

import { Button, Select } from 'element-ui'
Vue.use(Button)
Vue.use(Select)

Обратитесь к методу построения element-ui

babel-plugin-componentПлагин будет:

import { Button } from 'element-ui'

преобразуется в:

var button = require('element-ui/lib/button')
require('element-ui/lib/theme-chalk/button.css')

На указанном выше путиelement-uiа такжеtheme-chalkвсе настраивается,buttonимя компонента,libдаbabel-plugin-componentПлагин по умолчанию ищет папку компонента.

Если мы хотим использовать егоbabel-plugin-componentПлагин реализует более элегантные ссылки по запросу, поэтому каждый компонент упаковывается отдельно и помещается в библиотеку компонентов.lib文件.

Внедрение цитирования по требованию

Создаватьwebpack.component.js, файл конфигурации, упакованный отдельно как компонент. Напишите еще два компонента Hello и Test, которые в дальнейшем будут использоваться для тестирования.Поскольку компоненты упакованы отдельно, каждый компонент экспортирует функцию, которая выполняется при выполнении Vue.use(xx) для завершения глобальной регистрации компонента.

Hello/Hello.vueа такжеHello/index.js

//  src/index.js改成这样
import Hello from "./components/Hello"
import Test from "./components/Test"
function install(Vue){
  Vue.use(Hello)
  Vue.use(Test)
}
if(window && window.Vue) {
  Vue.use(install)
}
export default install

Реализация также очень проста, а ядро ​​является многофункциональной упаковкой.Вот многоразовая упаковка

мы будем впередиwebpack.config.jsСкопируйте и вставьте содержимоеwebpack.component.jsсередина.

  • Первый шаг, изменитьentryа такжеoutputПоле:
entry: {
  'hello': './src/components/Hello/index.js',
  'test': './src/components/Test/index.js',
  'my-lib': './src/index.js'
},
output: {
  path: path.join(__dirname,"/lib"),
  filename: '[name].js',
  libraryTarget: 'umd',
  library: '[name]',
  libraryExport: 'default'
},

Добавьте скрипты в package.json:"component": "webpack --config webpack.component.js"

npm run component

В каталоге компонента myLib есть дополнительная папка lib.

  • Второй шаг, из вышеперечисленногоelement-uiизbabel-plugin-componentПо тому, как используется плагин, мы видим, что файл js и файл css библиотеки компонентов разделены. Так же мы выделяем css компонента в отдельный файл, здесь мы используемmini-css-extract-pluginплагин.
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

Настройка завершена, сноваnpm run component

Затем измените package.json"main": "./lib/my-lib.js",

Вернемся к тестовому проекту. Создан в корневом каталоге проекта.babelrc (установите плагин согласно подсказкам командной строки), перезапустите проект.справочник по настройке компонента babel-plugin

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "my-lib",
        "styleLibrary": {
          "name": "lib-style", // same with styleLibraryName
          "base": false  // if theme package has a base.css
        }
      }
    ]
  ]
}

Проведем грубый тест. Обращайтесь только к компоненту hello, используя как hello, так и test.

//   LibTest/src/index.js
import { Hello } from "my-lib"
Vue.use(Hello)

//  LibTest/src/App.vue
<template>
    <div class="cp">
        <hello></hello>
        <test></test>
    </div>
</template>

Добавьте ссылку на тестовый компонент:

import { Hello,Test } from "my-lib"
Vue.use(Hello)
Vue.use(Test)

Затем мы удаляем ссылку на тестовый компонент. Упакуйте тестовый проект. Найдите в упакованном файле содержимое обоих компонентов.

Мы упаковали библиотеку компонентов vue, загружаемую по запросу. На самом деле, библиотека компонентов для разработки также может быть упакована с помощью rollup.js, который может хорошо поддерживать модуль ES, и встряска дерева также предлагается с помощью rollup.js.Гораздо проще реализовать загрузку библиотеки компонентов по требованию. На сегодня все, в следующей статье будет рассказ о том, как упаковать библиотеку с роллапом, увидимся в следующий раз.