Принцип Webpack — как реализовать упаковку кода

внешний интерфейс оптимизация производительности Webpack

无一.webp

Это 122-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в официальном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Принцип Webpack — как реализовать упаковку кода

предисловие

Webpack слишком хорошо знаком как интерфейсный «осадный лев». Webpack может делать слишком много вещей. Он может упаковывать все ресурсы (включая JS, TS, JSX, изображения, шрифты и CSS и т. д.) и помещать их в зависимости. , чтобы вы могли ссылаться на зависимости для использования ресурсов по мере необходимости. Webpack проделал большую работу по переводу нескольких интерфейсных файловых ресурсов, анализу сложных зависимостей модулей, и мы также можем настроить загрузчик для свободной загрузки наших собственных ресурсов.Как Webpack реализует упаковку? Приходите к нам сегодня.

Чтобы знать принцип упаковки Webpack, нам нужно знать два пункта знаний заранее.

1. Что требуется?

Когда дело доходит до требования, первое, что приходит на ум, это импорт, который является синтаксическим стандартом es6.

— require — это вызов во время выполнения, поэтому теоретически require может использоваться в любом месте кода;

— импорт вызывается во время компиляции, поэтому его необходимо разместить в начале файла;

Когда мы используем Webpack для компиляции, мы будем использовать babel для преобразования import в require.В CommonJS есть глобальный метод require(), который используется для загрузки модулей.AMD и CMD также используют метод require для ссылки.

Например:

var add = require('./a.js');
add(1,2)

Проще говоря, require на самом деле является функцией, которая относится к./a.jsПросто параметр функции.

2. Что такое экспорт?

Здесь мы можем подумать об экспорте - это объект,MDN export Вы можете увидеть конкретное использование.

Понять требовать и экспортировать, то мы можем начать упаковку

Давайте сначала посмотрим на структуру кода, которую мы упаковали ниже, мы можем обнаружить, что require и exports появятся после упаковки.

Не все браузеры могут выполнять require exports, вы должны реализовать require и exports самостоятельно, чтобы обеспечить нормальную работу кода. Упакованный код представляет собой самовыполняющуюся функцию.Параметры имеют информацию о зависимости и код файла.Исполняемое тело функции выполняет код через eval.

Общий дизайн выглядит следующим образом:

Шаг 1: Напишите наш файл конфигурации

Файл конфигурации сконфигурирован с записью Entry и упакованным экспортом Output, готовым к подготовке.

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),//打包后输出的文件地址,需要绝对路径因此需要path
    filename:"main.js"
  },
  mode:"development"
  

Шаг 2: Модульный анализ

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

Детали демонтажа: Некоторые люди могут задаться вопросом, почему используется AST, потому что AST родился с этой функцией. Его ImportDeclaration может помочь нам быстро отфильтровать синтаксис импорта. Конечно, возможно и обычное сопоставление. В конце концов, файл читается как строка. Регулярно получить путь зависимости файла, но это недостаточно элегантно.

Шаг 1: новые зависимости index.js, a.js, b.js выглядят следующим образом.

файл index.js

import { str } from "./a.js";
console.log(`${str} Webpack`)

файл .js

import { b} from "./b.js"
export const str = "hello"

b.js-файл

export const b="bbb"

Шаг 2: Напишите Webpack

модульный анализ: Используйте @babel/parser AST для преобразования строки, считанной из файла, в дерево AST, @babel/traverse для анализа синтаксиса и используйте ImportDeclaration для фильтрации импорта для поиска зависимостей файлов.

    const content = fs.readFileSync(entryFile, "utf-8");
    const ast = parser.parse(content, { sourceType: "module" });
  
    const dirname = path.dirname(entryFile);
    const dependents = {};
    traverse(ast, {
      ImportDeclaration({ node }) {
        // 过滤出import
        const newPathName = "./" + path.join(dirname, node.source.value);
        dependents[node.source.value] = newPathName;
      }
    })
    const { code } = transformFromAst(ast, null, {
      presets: ["@babel/preset-env"]
    })
    return {
      entryFile,
      dependents,
      code
    }
    

Результат выглядит следующим образом:

Используйте рекурсию или цикл для импорта файлов один за другим для анализа зависимостей.Обратите внимание, что мы используем цикл for для анализа всех зависимостей.Причина, по которой цикл может анализировать все зависимости, обратите внимание на то, что длина модулей изменяется, когда есть зависимости. Модули .push новые зависимости, modules.length изменится.

 for (let i = 0; i < this.modules.length; i++) {
      const item = this.modules[i];
      const { dependents } = item;
      if (dependents) {
        for (let j in dependents) {
​
          this.modules.push(this.parse(dependents[j]));
        }
​
      }
    }

Шаг 3: Напишите функцию WebpackBootstrap + сгенерируйте выходные файлы

записывать WebpackBootstrap функция:Первое, что нам нужно сделать здесь, это функция WebpackBootstrap.После компиляции импорт нашего исходного кода будет разобран в require.Поскольку браузер не знает require,объявим его первым.Ведь require это метод , и нам это нужно при написании функций.Обратите внимание, что изоляция области видимости предотвращает загрязнение переменных. Нам также необходимо объявить экспорты в нашем коде, чтобы гарантировать, что экспорты уже существуют, когда код выполняется.

Создать выходной файл: Мы прописали адрес сгенерированного файла в конфигурационный файл, а затем с помощью fs.writeFileSync записали его в выходную папку.

  file(code) {
    const filePath = path.join(this.output.path, this.output.filename)
    const newCode = JSON.stringify(code);
    // 生成bundle文件内容
    const bundle = `(function(modules){
      function require(module){
        function pathRequire(relativePath){
          return require(modules[module].dependents[relativePath])
        }
        const exports={};
        (function(require,exports,code){
          eval(code)
        })(pathRequire,exports,modules[module].code);
        return exports
      }
      require('${this.entry}')
    })(${newCode})`;
      //  WebpackBoostrap
    // 生成文件。放入dist 目录
    fs.writeFileSync(filePath,bundle,'utf-8')
  }
  

Шаг 4: Анализ порядка выполнения

Мы можем запустить упакованный результат в консоли браузера, если он работает, должен быть распечатан hello Webpack.

Суммировать

Благодаря приведенному выше анализу у нас должно быть общее представление об общем процессе Webpack. Использование AST для анализа кода — это только способ этой демонстрации, а не реальная реализация Webpack. Webpack имеет свой собственный метод анализа AST, который неотделим. Главное получить зависимости модулей.Экосистема Webpack очень полная.Заинтересованная детская обувь может рассмотреть следующие три вопроса:

  • Что делать, если есть циклическая ссылка компонента?
  • Как Webpack загружает загрузчики?
  • Очень рекомендуемый Иудой vite можно упаковывать по запросу, что сильно снижает скорость упаковки при разработке.Если это webapck, то как его реализовать?

Рекомендуемое чтение

Почему не рекомендуется использовать индекс в качестве ключа в Vue

Анализ технической схемы и реализация записи веб-экрана

работы с открытым исходным кодом

  • Zhengcaiyun интерфейсный таблоид

адрес с открытым исходным кодомwww.zoo.team/openweekly/(На главной странице официального сайта таблоида есть группа обмена WeChat)

  • Плагин выбора товара

адрес с открытым исходным кодомGitHub.com/Chinese Patent Medicine-Inc/Reservoir…

Карьера

ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 60 фронтенд-партнеров, средний возраст которых 27 лет, и почти 40% из них — инженеры с полным стеком, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.

Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com