Простой и понятный процесс запуска JS после упаковки webpack

внешний интерфейс GitHub JavaScript Webpack

привет~ Уважаемые наблюдатели и господа, привет всем~ Недавно я изучал соответствующие знания о веб-пакете, когда я ясно понялwebpackпросто другойloaderиpluginПосле объединения и упаковки он используется только как инструмент, который считается записью. Конечно, я столкнулся с бесчисленными ямами в процессе, и я также хотел узнать об этом больше.webpackПринцип (в основном попадаешь в яму и вылезаешь сам). Итак, начните с простого, сначала посмотрите на использованиеwebpackв упаковкеJSКак загружается файл.

Дружеское напоминание, эта статья проста и понятна, даже если она не использовалась.webpackБез проблем. Если вы уже усвоили соответствующие знания, вы можете быстро прочитать их, что расценивается как просмотр прошлого и изучение нового.На самом деле, я хочу, чтобы ты сказал мне, где я не прав..

Простая конфигурация

Так как необходимо использоватьwebpack, надо еще настроить просто, вот простой код вставить, в первую очередьwebpack.config.js:

const path = require('path');
const webpack = require('webpack');
//用于插入html模板
const HtmlWebpackPlugin = require('html-webpack-plugin');
//清除输出目录,免得每次手动删除
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  entry: {
    index: path.join(__dirname, 'index.js'),
  },
  output: {
    path: path.join(__dirname, '/dist'),
    filename: 'js/[name].[chunkhash:4].js'
  },
  module: {},
  plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
    }),
    //持久化moduleId,主要是为了之后研究加载代码好看一点。
    new webpack.HashedModuleIdsPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'manifest',
    })
  ]
};

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

затем два простыхjsдокумент:

// test.js
const str = 'test is loaded';
module.exports = str;

// index.js
const test = require('./src/js/test');
console.log(test);

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

На этом наша конфигурация завершена.

отindex.jsначать смотреть код

Первый из упакованныхindex.htmlфайл смотреть на дваJSПорядок загрузки файлов:

<body>
	<script type="text/javascript" src="js/manifest.2730.js"></script>
	<script type="text/javascript" src="js/index.5f4f.js"></script>
</body>

Как видите, после упаковкиjsФайлы загружаются в первом порядкеmanifest.js, а потомindex.js, надо сначала посмотретьmanifest.jsсодержания. Однако давайте сначала продадим его здесь, давайте посмотримindex.jsКаково содержаниеmanifest.js, то есть какова логика основного процесса и почему он может быть модульным.

// index.js

webpackJsonp([0], {
  "JkW7": (function(module, exports, __webpack_require__) {
    const test = __webpack_require__("zFrx");
    console.log(test);
  }),
  "zFrx": (function(module, exports) {
    const str = 'test is loaded';
    module.exports = str;
  })
}, ["JkW7"]);

После удаления всяких странных комментариев контента осталось так мало.Первое на что стоит обратить внимание этоwebpackJsonpЭта функция, вы можете видеть, что она не находится ни под каким пространством имен, то естьmanifest.jsследует определитьwindowГлобальная функция под,index.jsПередайте три параметра этой функции и вызовите ее.

Первый параметр — это массив, и пока непонятно, что этот массив делает.

Второй параметр — это объект, заполненный методами, которые, по-видимому, принимают как минимум два параметра (названныхzFrxметод имеет только два параметра). Взглянув внутрь этих двух методов, я на самом деле вижу что-то очень знакомое,module.exports, хоть и невидимыйrequire, но по внешнему виду похож на__webpack_require__, эти две функции должны быть ключом к модульности, сначала обратите внимание на эти две функции.

Третий параметр тоже массив, и непонятно что он делает, но заметим, что его значение равноJkW7, что соответствует ключу метода в параметре 2, который может иметь некоторую логическую связь.

Уже,index.jsСодержаниеmanifest.jsнайти ответ.

manifest.jsчтение кода

Поскольку сжатие не настроеноjsвариант, такmanifest.jsИсходный код составляет около 150 строк, и он упрощен до 28 строк (код был запущен, и фактическое измерение не представляет проблемы). Ввиду того, что упрощенного кода на самом деле не так много, поэтому сначала я выложу код.По только что поднятым вопросам посмотрим, сколько ответов мы сможем найти:

(function(modules) {
  window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
    var moduleId, result;
    for (moduleId in moreModules) {
      if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
        modules[moduleId] = moreModules[moduleId];
      }
    }
    if (executeModules) {
      for (i = 0; i < executeModules.length; i++) {
        result = __webpack_require__(executeModules[i]);
      }
    }
    return result;
  };
  var installedModules = {};

  function __webpack_require__(moduleId) {
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    var module = installedModules[moduleId] = {
      exports: {}
    };
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    return module.exports;
  }
})([]);

Первое, что вы должны увидеть, это то,manifest.jsвнутри находитсяIIFE, является самовыполняющейся функцией, эта функция примет в качестве параметра пустой массив, имя массиваmodules. а потом увидел, что мыindex.jsГипотеза вwindowНа нем есть имяwebpackJsonpФункция. Он принимает три параметра с именемchunkIds, moreModules, executeModules. соответствуетindex.jsвызыватьwebpackJsonpПереданы три параметра. иwebpackJsonpКакая логика внутри?

Независимо от установленных параметров,webpackJsonpпервыйfor inпройдено один разmoreModules,будетmoreModulesВсе методы внутри существуютmodules, который является массивом, передаваемым при выполнении самовыполняющейся функции.

После этого условное суждение:

if (executeModules) {
  for (i = 0; i < executeModules.length; i++) {
    result = __webpack_require__(executeModules[i]);
  }
}

судитьexecuteModules, то есть существует ли третий параметр, если он есть, то он будет выполнен__webpack_require__метод. существуетindex.jsперечислитьwebpackJsonpметод, этот параметр, конечно, существует, так что посмотрите на__webpack_require__Что такое метод.

__webpack_require__принимаетmoduleIdпараметр. Внутри метода находится сначала условное суждение, независимо от того. Далее см. логику назначения

var module = installedModules[moduleId] = {
  exports: {}
};

В сочетании с предыдущим условным суждением можно сделать вывод, чтоinstalledModulesявляется кешированным контейнером, то предыдущий код означает, что если в кеше есть соответствующий кешmoduleId, затем напрямую вернуть егоexports, в противном случае определите и назначьте его. Тогда взгляните__webpack_require__Последнее возвращаемое значение , вы можете видеть, что функция возвращаетmodule.exports,Такmodule.exportsКак он назначается? Взгляните на код после:

modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

только сейчас мы знаемmodules[moduleId]этоmoreModulesметод в , вотthisНазначенmodule.exports, затем поставьтеmodule, module.exports, __webpack_require__Передайте его в качестве параметра для вызова. Вам знакомы эти три параметра? прежде чем мы увиделиindex.jsПри написании кода внутри возникает вопрос, как достигается модульность. Здесь мы увидели глаз.

фактическиwebpackзаключается в том, чтобы положить каждыйjsФайл инкапсулирован в функцию,requireметод соответствует__webpack_require__,__webpack_require__будет основываться на поступающихmoduleIdЗатем загрузите соответствующий код. И когда мы хотим экспортироватьjsзначение файла, либо используйтеmodule.exportsили используйтеexports, что соответствуетmodule, module.exportsдва параметра. Если вы не прикасаетесь к этому предмету детской обуви, вы должны понять, почему вы используете его непосредственно при экспорте значений.exports = xxxЭкспорт не удастся. Простой пример:

const module = {
  exports: {}
};

function demo1(module) {
  module.exports = 1;
}

demo1(module);
console.log(module.exports); // 1

function demo2(exports) {
  exports = 2;
}

demo2(module.exports);
console.log(module.exports); // 1

Вставьте этот код и запустите его в браузере, и вы обнаружите, что оба отпечатка равны 1. с участиемwenpackЛогика упаковки точно такая же.

Чтобы разобраться в процессе выполнения кода после упаковки, сначалаminifest.jsопределитwebpackJsonpметод, ожидая другие упакованные файлы (также называемыеchunk)перечислить. при звонкеchunk, это будет сначалаchunkвсе вmoreModules, то есть каждый зависимый файл также может называтьсяmodule(какtest.js)спасти. проходить послеexecuteModulesОпределите, является ли этот файл файлом входа, и решите, выполнять ли его в первый раз.__webpack_require__. и__webpack_require__, основано на этомmoduleМестоrequireВещи, постоянные рекурсивные вызовы__webpack_require__,__webpack_require__После того, как функция вернет значениеrequireиспользовать. Разумеется, модули не перезагружаются, т.к.installedModulesзаписаноmoduleпосле звонкаexportsЗначение , пока кеш попал, соответствующее значение будет возвращено без повторного вызоваmodule.webpackУпакованные файлы изолируются функциями один за другимmoduleмасштаб, чтобы достичь цели не загрязнять друг друга.

резюме

Вышеупомянутоеwebpackпосле упаковкиjsФайл представляет собой простое описание процесса загрузки, на самом деле осталось еще много незаконченных деталей, например, как асинхронно загрузить соответствующий модуль,chunkIdКакую роль он играет и т. д., но из-за нехватки места(еще не исследовал), без подробностей. Соответствующий код будет размещенgithub, пожалуйста, не стесняйтесь проверить случайную точкуstar.

Спасибо всем судьям за то, что увидели это, легче сказать, чем сделать, надеюсь, эта статья будет вам полезна~ Спасибо!