Après avoir lu les principes d'emballage de sac de papier que vous connaissez webpack

page de navigation blog personnel (cliquez sur le droit lien pour ouvrir un blog personnel): Daniel vous prenez sur la pile de technologie 

Qu'est-ce que webpack?

Essentiellement, webpack est une application moderne du module de garniture d'étanchéité statique JavaScript (module bundler). Lorsque les applications de traitement webpack, il construire récursivement un graphe de dépendance (graphe de dépendance), dans lequel chaque module comprend l'application souhaitée, l'ensemble de ces modules sont ensuite conditionnés dans un ou plusieurs de l'ensemble.

webpack comme une ligne de production, après avoir traversé une série de processus de traitement pour convertir le fichier source à la sortie. Chacune des fonctions de ce processus est une seule ligne de production, il existe des dépendances entre plusieurs processus, et seulement après terminé le processus en cours peut être remis au prochain processus à traiter. Comme un bouchon inséré dans une ligne de production fonctionnelle, faire les ressources de traitement sur la ligne de production à un moment donné.
webpack d'organiser ce complexe chaîne de production par Tapable. webpack pendant le fonctionnement diffusera l'événement, il suffit de brancher doit écouter les événements d'intérêt, peuvent être ajoutés à cette ligne de production, pour modifier le fonctionnement de la ligne de production. webpack le mécanisme de flux d'événements pour que les plug - ins ordonnés, rendant ainsi toute l'évolutivité du système. - simple , webpack Wu Haolin

concepts de base WebPack

Entrée

le point de départ d'entrée (point d'entrée) webpack indique quel module doit être utilisé pour la construction que le graphe de dépendance interne commence.

Après l'entrée du point de départ, webpack trouvera quels modules et les bibliothèques sont le point d'entrée de départ (directe et indirecte) à charge.

Chaque dépendance est ensuite traitée dans un fichier de sortie final appelé en faisceaux.

Production

attribut de sortie indique la sortie webpack où il a créé faisceaux, et comment nommer les fichiers, la valeur par défaut ./dist.

En fait, toute la structure d'application, sera compilé dans un fichier que vous spécifiez le dossier de chemin de sortie.

Module

Module, où tout est dans le module Webpack, un module correspond à un fichier. Webpack sera configuré pour démarrer à partir l'entrée récursive trouver tous les modules dépendants.

Tronçon

bloc de code, une combinaison d'une pluralité de modules réalisés en morceaux, le code pour la fusion et la segmentation.

Chargeur

chargeur marque webpack en mesure de traiter ces fichiers non JavaScript (lui-même webpack comprendre que JavaScript).

chargeur peut convertir tous les types de fichiers est le module valide webpack peut gérer, vous pouvez utiliser webpack capacité emballés, et de les traiter.

Essentiellement, webpack chargeur tous les types de fichiers, est converti au schéma de dépendance du module de l'application (et éventuellement le faisceau) peut être référencé directement.

Brancher

Le chargeur est utilisé pour convertir certains types de blocs, prise peuvent être utilisés pour effectuer une plus large gamme de tâches.

Gamme de plug-ins comprennent, d'optimisation des emballages et à la compression, tout le chemin de redéfinir la variable d'environnement. Interface du plugin extrêmement puissant, peut être utilisé pour traiter une variété de tâches.

Procédé de construction webpack

Webpack processus en cours d'exécution est un processus de série, les procédures suivantes seront suivies du début à la fin:

  1. paramètres d'initialisation: paramètres de lecture des fichiers de configuration et fusion déclaration Shell, obtenir les paramètres finaux.
  2. Démarrer la compilation: les paramètres d'initialisation du compilateur passent l'étape cible charge obtenue tout plug-in configuration, méthode run effectue objet a commencé à compiler.
  3. OK Entrée: trouvez toutes les entrées dans l'entrée du fichier de configuration.
  4. Compiler le module: A partir du fichier d'entrée, appelez la configuration du chargeur de tous les modules de traduction, puis trouver le module dépendant module, puis récursive cette étape jusqu'à ce que tous les fichiers ont été dépendants à l'entrée du processus dans cette étape.
  5. Module de compilation complète: après l'étape 4 en utilisant la fin Loader traduire tous les modules, chaque module obtenu après le contenu final est traduit et les dépendances entre eux.
  6. Ressources de sortie: les dépendances entre l'entrée et les modules sont assemblés en une pluralité de modules contenant un seul bloc et en morceaux puis convertir chacun en un seul fichier de sortie sur la liste, cette étape est la dernière occasion de modifier le contenu de sortie .
  7. achèvement sortie: Après avoir déterminé le contenu du puits de sortie, en fonction de la configuration afin de déterminer la sortie du chemin d'accès et le nom du fichier, le contenu du fichier sont écrites dans le système de fichiers.

Dans le processus ci-dessus, Webpack diffusera un événement spécial à un point précis dans le temps, après avoir écouté brancher l'événement d'intérêt effectuera une logique spécifique, et les plug-ins peuvent appeler l'API webpack fournir un changement des résultats d'exploitation Webpack.

Pratique à approfondir la compréhension, une ligne simple et webpack

1. Définition classe du compilateur

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {}
  // 重写 require函数,输出bundle
  generate() {}
}

2. Parse les documents de d'entrée, l'accès à l'AST

Ici, nous utilisons le @ babel / analyseur qui est des outils de babel7 pour nous aider à analyser la grammaire interne, y compris ES6, un arbre AST retour de syntaxe abstraite.

// webpack.config.js

const path = require('path')
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'main.js'
  }
}
//
const fs = require('fs')
const parser = require('@babel/parser')
const options = require('./webpack.config')

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    const ast = Parser.getAst(this.entry)
  }
  // 重写 require函数,输出bundle
  generate() {}
}

new Compiler(options).run()

3. Trouver tous les modules dépendants

Babel fournit @ babel / traverse (traverse) méthode pour maintenir l'état général de cet arbre AST, ici nous l'utilisons pour nous aider à identifier les modules dépendants.

const fs = require('fs')
const path = require('path')
const options = require('./webpack.config')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  },
  getDependecies: (ast, filename) => {
    const dependecies = {}
    // 遍历所有的 import 模块,存入dependecies
    traverse(ast, {
      // 类型为 ImportDeclaration 的 AST 节点 (即为import 语句)
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename)
        // 保存依赖模块路径,之后生成依赖关系图需要用到
        const filepath = './' + path.join(dirname, node.source.value)
        dependecies[node.source.value] = filepath
      }
    })
    return dependecies
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    const { getAst, getDependecies } = Parser
    const ast = getAst(this.entry)
    const dependecies = getDependecies(ast, this.entry)
  }
  // 重写 require函数,输出bundle
  generate() {}
}

new Compiler(options).run()

4. AST est converti en code

L'arbre de syntaxe AST dans un code exécutable du navigateur, nous utilisons ici @ babel / core et @ babel / préprogrammée env.

const fs = require('fs')
const path = require('path')
const options = require('./webpack.config')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const { transformFromAst } = require('@babel/core')

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  },
  getDependecies: (ast, filename) => {
    const dependecies = {}
    // 遍历所有的 import 模块,存入dependecies
    traverse(ast, {
      // 类型为 ImportDeclaration 的 AST 节点 (即为import 语句)
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename)
        // 保存依赖模块路径,之后生成依赖关系图需要用到
        const filepath = './' + path.join(dirname, node.source.value)
        dependecies[node.source.value] = filepath
      }
    })
    return dependecies
  },
  getCode: ast => {
    // AST转换为code
    const { code } = transformFromAst(ast, null, {
      presets: ['@babel/preset-env']
    })
    return code
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    const { getAst, getDependecies, getCode } = Parser
    const ast = getAst(this.entry)
    const dependecies = getDependecies(ast, this.entry)
    const code = getCode(ast)
  }
  // 重写 require函数,输出bundle
  generate() {}
}

new Compiler(options).run()

La résolution récursive toutes les dépendances, générer une figure de dépendance.

const fs = require('fs')
const path = require('path')
const options = require('./webpack.config')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const { transformFromAst } = require('@babel/core')

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  },
  getDependecies: (ast, filename) => {
    const dependecies = {}
    // 遍历所有的 import 模块,存入dependecies
    traverse(ast, {
      // 类型为 ImportDeclaration 的 AST 节点 (即为import 语句)
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename)
        // 保存依赖模块路径,之后生成依赖关系图需要用到
        const filepath = './' + path.join(dirname, node.source.value)
        dependecies[node.source.value] = filepath
      }
    })
    return dependecies
  },
  getCode: ast => {
    // AST转换为code
    const { code } = transformFromAst(ast, null, {
      presets: ['@babel/preset-env']
    })
    return code
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    // 解析入口文件
    const info = this.build(this.entry)
    this.modules.push(info)
    this.modules.forEach(({ dependecies }) => {
      // 判断有依赖对象,递归解析所有依赖项
      if (dependecies) {
        for (const dependency in dependecies) {
          this.modules.push(this.build(dependecies[dependency]))
        }
      }
    })
    // 生成依赖关系图
    const dependencyGraph = this.modules.reduce(
      (graph, item) => ({
        ...graph,
        // 使用文件路径作为每个模块的唯一标识符,保存对应模块的依赖对象和文件内容
        [item.filename]: {
          dependecies: item.dependecies,
          code: item.code
        }
      }),
      {}
    )
  }
  build(filename) {
    const { getAst, getDependecies, getCode } = Parser
    const ast = getAst(filename)
    const dependecies = getDependecies(ast, filename)
    const code = getCode(ast)
    return {
      // 文件路径,可以作为每个模块的唯一标识符
      filename,
      // 依赖对象,保存着依赖模块路径
      dependecies,
      // 文件内容
      code
    }
  }
  // 重写 require函数,输出bundle
  generate() {}
}

new Compiler(options).run()

6. à réécrire la fonction, le faisceau de sortie

const fs = require('fs')
const path = require('path')
const options = require('./webpack.config')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const { transformFromAst } = require('@babel/core')

const Parser = {
  getAst: path => {
    // 读取入口文件
    const content = fs.readFileSync(path, 'utf-8')
    // 将文件内容转为AST抽象语法树
    return parser.parse(content, {
      sourceType: 'module'
    })
  },
  getDependecies: (ast, filename) => {
    const dependecies = {}
    // 遍历所有的 import 模块,存入dependecies
    traverse(ast, {
      // 类型为 ImportDeclaration 的 AST 节点 (即为import 语句)
      ImportDeclaration({ node }) {
        const dirname = path.dirname(filename)
        // 保存依赖模块路径,之后生成依赖关系图需要用到
        const filepath = './' + path.join(dirname, node.source.value)
        dependecies[node.source.value] = filepath
      }
    })
    return dependecies
  },
  getCode: ast => {
    // AST转换为code
    const { code } = transformFromAst(ast, null, {
      presets: ['@babel/preset-env']
    })
    return code
  }
}

class Compiler {
  constructor(options) {
    // webpack 配置
    const { entry, output } = options
    // 入口
    this.entry = entry
    // 出口
    this.output = output
    // 模块
    this.modules = []
  }
  // 构建启动
  run() {
    // 解析入口文件
    const info = this.build(this.entry)
    this.modules.push(info)
    this.modules.forEach(({ dependecies }) => {
      // 判断有依赖对象,递归解析所有依赖项
      if (dependecies) {
        for (const dependency in dependecies) {
          this.modules.push(this.build(dependecies[dependency]))
        }
      }
    })
    // 生成依赖关系图
    const dependencyGraph = this.modules.reduce(
      (graph, item) => ({
        ...graph,
        // 使用文件路径作为每个模块的唯一标识符,保存对应模块的依赖对象和文件内容
        [item.filename]: {
          dependecies: item.dependecies,
          code: item.code
        }
      }),
      {}
    )
    this.generate(dependencyGraph)
  }
  build(filename) {
    const { getAst, getDependecies, getCode } = Parser
    const ast = getAst(filename)
    const dependecies = getDependecies(ast, filename)
    const code = getCode(ast)
    return {
      // 文件路径,可以作为每个模块的唯一标识符
      filename,
      // 依赖对象,保存着依赖模块路径
      dependecies,
      // 文件内容
      code
    }
  }
  // 重写 require函数 (浏览器不能识别commonjs语法),输出bundle
  generate(code) {
    // 输出文件路径
    const filePath = path.join(this.output.path, this.output.filename)
    // 懵逼了吗? 没事,下一节我们捋一捋
    const bundle = `(function(graph){
      function require(module){
        function localRequire(relativePath){
          return require(graph[module].dependecies[relativePath])
        }
        var exports = {};
        (function(require,exports,code){
          eval(code)
        })(localRequire,exports,graph[module].code);
        return exports;
      }
      require('${this.entry}')
    })(${JSON.stringify(code)})`

    // 把文件内容写入到文件系统
    fs.writeFileSync(filePath, bundle, 'utf-8')
  }
}

new Compiler(options).run()

7. Après avoir lu cette section, de connaître le faisceau complet pour atteindre

Nous expliquons dans l'exemple suivant, la première mort stare 30 secondes

;(function(graph) {
  function require(moduleId) {
    function localRequire(relativePath) {
      return require(graph[moduleId].dependecies[relativePath])
    }
    var exports = {}
    ;(function(require, exports, code) {
      eval(code)
    })(localRequire, exports, graph[moduleId].code)
    return exports
  }
  require('./src/index.js')
})({
  './src/index.js': {
    dependecies: { './hello.js': './src/hello.js' },
    code: '"use strict";\n\nvar _hello = require("./hello.js");\n\ndocument.write((0, _hello.say)("webpack"));'
  },
  './src/hello.js': {
    dependecies: {},
    code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.say = say;\n\nfunction say(name) {\n  return "hello ".concat(name);\n}'
  }
})

étape 1: a commencé à partir du fichier d'entrée

// 定义一个立即执行函数,传入生成的依赖关系图
;(function(graph) {
  // 重写require函数
  function require(moduleId) {
    console.log(moduleId) // ./src/index.js
  }
  // 从入口文件开始执行
  require('./src/index.js')
})({
  './src/index.js': {
    dependecies: { './hello.js': './src/hello.js' },
    code: '"use strict";\n\nvar _hello = require("./hello.js");\n\ndocument.write((0, _hello.say)("webpack"));'
  },
  './src/hello.js': {
    dependecies: {},
    code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.say = say;\n\nfunction say(name) {\n  return "hello ".concat(name);\n}'
  }
})

étape 2: exécuter le code en utilisant eval

// 定义一个立即执行函数,传入生成的依赖关系图
;(function(graph) {
  // 重写require函数
  function require(moduleId) {
    ;(function(code) {
      console.log(code) // "use strict";\n\nvar _hello = require("./hello.js");\n\ndocument.write((0, _hello.say)("webpack"));
      eval(code) // Uncaught TypeError: Cannot read property 'code' of undefined
    })(graph[moduleId].code)
  }
  // 从入口文件开始执行
  require('./src/index.js')
})({
  './src/index.js': {
    dependecies: { './hello.js': './src/hello.js' },
    code: '"use strict";\n\nvar _hello = require("./hello.js");\n\ndocument.write((0, _hello.say)("webpack"));'
  },
  './src/hello.js': {
    dependecies: {},
    code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.say = say;\n\nfunction say(name) {\n  return "hello ".concat(name);\n}'
  }
})

Vous pouvez le voir, nous sommes donné au moment de l'exécution « ./src/index.js » code du fichier, car index.js dans hello.js dépendant de référence, mais nous ne doivent pas compter sur des aliments transformés, nous comptons sur des références à pour le traitement.

étape 3: la charge des objets de mappage d'adresses, l'objet acquis exportations

// 定义一个立即执行函数,传入生成的依赖关系图
;(function(graph) {
  // 重写require函数
  function require(moduleId) {
    // 找到对应moduleId的依赖对象,调用require函数,eval执行,拿到exports对象
    function localRequire(relativePath) {
      return require(graph[moduleId].dependecies[relativePath]) // {__esModule: true, say: ƒ say(name)}
    }
    // 定义exports对象
    var exports = {}
    ;(function(require, exports, code) {
      // commonjs语法使用module.exports暴露实现,我们传入的exports对象会捕获依赖对象(hello.js)暴露的实现(exports.say = say)并写入
      eval(code)
    })(localRequire, exports, graph[moduleId].code)
    // 暴露exports对象,即暴露依赖对象对应的实现
    return exports
  }
  // 从入口文件开始执行
  require('./src/index.js')
})({
  './src/index.js': {
    dependecies: { './hello.js': './src/hello.js' },
    code: '"use strict";\n\nvar _hello = require("./hello.js");\n\ndocument.write((0, _hello.say)("webpack"));'
  },
  './src/hello.js': {
    dependecies: {},
    code:
      '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n  value: true\n});\nexports.say = say;\n\nfunction say(name) {\n  return "hello ".concat(name);\n}'
  }
})

Cette fois-ci devrait comprendre - peut être copié directement à la sortie de la console du code ci-dessus oh ~

résumé

Webpack est une énorme demande Node.js, si vous lisez son code source, vous trouverez une réalisation complète de besoin webpack d'écrire beaucoup de code. Mais vous n'avez pas besoin de connaître tous les détails, juste pour comprendre l'architecture globale et certains détails peuvent être.

Webpack de l'utilisateur, il est un simple mais puissant outil, webpack pour les développeurs, il est un système hautement évolutif.

Webpack a été en mesure de réussir, il se trouve dans la cachette de mise en œuvre complexe, exposée à l'utilisateur est un outil simple qui permet aux utilisateurs d'atteindre rapidement l'objectif. En même temps, la structure globale de la conception raisonnable, une grande évolutivité, de développer des difficultés d'extensions n'est pas élevé, par marque communautaire un grand nombre de fonctionnalités manquantes qui font Webpack presque qualifié pour une scène.

Attaché Java / C / C ++ / apprentissage machine / algorithmes et structures de données / front-end / Android / Python / programmeur de lecture / Livres Livres simples Daquan:

(Cliquez sur le droit d'ouvrir là - bas dans le blog personnel sec): sec technique Floraison
===== >> ① [Java Daniel vous prendre sur la route à avancé] << ====
===== >> ② [+ acm algorithme structure de données Daniel vous prendre sur la route à avancé] << ===
===== >> ③ [base de données Daniel vous prendre sur la route à avancé] << == ===
===== >> ④ [Daniel Web front-end pour vous emmener sur la route à avancé] << ====
===== >> ⑤ [ la machine python d'apprentissage et Daniel vous prenez l' entrée à la route avancée] << ====
===== >> ⑥ [architecte Daniel vous prendre sur la route à avancé] << =====
===== >> ⑦ [C ++ Daniel avance pour vous emmener sur la route] << ====
===== >> ⑧ [ios Daniel vous prendre sur la route à avancé] << ====
=====> > ⑨ [sécurité Web Daniel vous prendre sur la route à avancé] << =====
===== >> ⑩ [système d'exploitation Linux et Daniel vous prenez la route à avancé] << = ====

Il n'y a pas de fruits non acquises, espérons que vous jeunes amis, les amis veulent apprendre les techniques, surmonter tous les obstacles sur le chemin de la route déterminée à lier dans la technologie, de comprendre le livre, puis frapper sur le code, comprendre le principe, et aller pratique, sera il vous apportera la vie, votre travail, votre avenir un rêve.

Publié 47 articles originaux · louanges gagnées 0 · Vues 283

Je suppose que tu aimes

Origine blog.csdn.net/weixin_41663412/article/details/104863745
conseillé
Classement