Webpack4.x的四个核心概念介绍

目录
  • 一. 概念
    • 1. 入口
      • 1.1 基础概念
      • 1.2 单文件入口
      • 1.3 多文件入口
    • 2. 出口
      • 2.1 基础概念
      • 2.2 使用占位符来为每个文件命名,保证名称唯一
      • 2.3 使用CDN和资源hash
    • 3. loader
      • 3.1 基础概念
      • 3.2 安装并使用loader
      • 3.3 使用loader的三种方式
      • 3.4 loader加载顺序
      • 3.5 loader 特性
    • 4. 插件
      • 4.1 基础概念
      • 4.2 核心知识
    • 5. 模式
  • 二. 配置
    • 1. 基本配置
    • 2. 多种配置
      • 2.1 导出为一个函数
      • 2.2 导出为一个 Promise
      • 2.3 导出多个配置对象
    • 3. 使用其他配置语言
      • 3.1 TypeScript
      • 3.2 Babel and JSX
  • 三. 模块
    • 1. 模块介绍
    • 2. 模块解析
    • 3. 解析 loader
    • 4. 缓存
  • 四. 构建目标
    • 1. 用法
    • 2. 多个 target

一. 概念

需要理解四个核心概念

  • 入口(entry)
  • 输出(output)
  • loader
  • 插件(plugins)

1. 入口

1.1 基础概念

指定 webpack 由哪个模块作为项目构建的开始。

通过配置 entry 属性,指定一个或多个起点,默认值 ./src :

module.exports = {
  entry: './path/leo/file.js'
};

1.2 单文件入口

用法:entry: string|Array

当 entry 中没有配置入口的文件对象的名称,默认使用的是 main 名称,输出就是 main.js,即:

// 默认情况
module.exports = {
  entry: './path/leo/file.js'
};

// 配置单个入口
const config = {
  entry: {
    main: './path/leo/file.js'
  }
};

可以看出,实际上 默认情况 只是 配置单个入口 的简写形式。

另外,文件路径我们也可以传入一个数组,就会将多个依赖文件一起注入:

const config = {
  entry: {
    main: ['./path/leo/file.js', './path/leo/index.js', './path/leo/server.js']
  }
};

1.3 多文件入口

用法:entry: {[entryChunkName: string]: string|Array}

多个文件完全分离互相独立(每个 bundle 中都有一个 webpack 引导(bootstrap)),常见于只有一个入口的单页面应用。

const config = {
  entry: {
    app: './src/app.js',
    vendors: './src/vendors.js'
  }
};

2. 出口

2.1 基础概念

指定 webpack 最终输出的文件输出位置和文件名等信息。

通过配置 output 属性,指定输出位置和文件名,默认输出位置为 ./dist :

两个属性:

  • path :输出的目录绝对路径;
  • filename :输出的文件名称;
const path = require('path');
module.exports = {
  entry: './path/leo/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'leo-webpack.bundle.js'
  }
};

2.2 使用占位符来为每个文件命名,保证名称唯一

  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  }

更多占位符,点击查看

2.3 使用CDN和资源hash

output: {
  path: "/home/proj/cdn/assets/[hash]",
  publicPath: "http://cdn.example.com/assets/[hash]/"
}

关于output.publicPath , 点击查看

如果编译时不知道最终文件的 publicPath ,可以留空,并在入口文件中动态设置。或者在入口起点设置 __webpack_public_path__ 来忽略它。

__webpack_public_path__ = myRuntimePublicPath

3. loader

3.1 基础概念

让 webpack 能够处理非 JS 文件,在 import 或 “加载”模块时预处理文件。

通过配置 loader 两个属性来实现:

  • test 属性,用来标识出应该被对应的 loader 进行转换的某个或多个文件;
  • use 属性,表示转换时要用哪个 loader;
const path = require('path');
const config = {
  output: {
    filename: 'leo-webpack.bundle.js'
  },
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  }
};
module.exports = config;

3.2 安装并使用loader

如安装一个 css-loader 和 ts-loader 使得 webpack 可以加载 CSS 文件,或者将 TypeScript 转换成 JavaScript

npm install --save-dev css-loader ts-loader

使用:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};

3.3 使用loader的三种方式

  • 配置(推荐):在 webpack.config.js 文件中指定 loader。

指定多个loader:

  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          }
        ]
      }
    ]
  }
  • 内联:在每个 import 语句中显式指定 loader。

可以在 import 语句或任何等效于 import 的方式中指定 loader,使用 ! 将多个 loader 分开,每个部分都是相对于当前目录的解析。

import Styles from 'style-loader!css-loader?modules!./styles.css';

尽可能使用 module.rules,减少代码量,并且在出错时,更快地调试和定位 loader 中的问题。

  • CLI:在 shell 命令中指定它们。
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

3.4 loader加载顺序

loader 会从数组最后一个开始,往前一个一个加载:

// webpack.config.js
module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: ['style-loader', 'css-loader'] },
    ]
  }
};

3.5 loader 特性

  • loader 支持链式传递。
  • 能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何可能的操作。
  • loader 接收查询参数。用于对 loader 传递配置。
  • loader 也能够使用 options 对象进行配置。
  • 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
  • 插件(plugin)可以为 loader 带来更多特性。
  • loader 能够产生额外的任意文件。

另外可以查看 如何编写 loader

4. 插件

4.1 基础概念

让 webpack 能够执行更多任务,从优化和压缩,到重新定义环境中的变量,非常强大。

插件目的在于解决 loader 无法实现的其他事。

使用时,只需要 require 它,并添加到 plugins 数组,通过 new 实例化即可:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装 const webpack = require('webpack'); // 用于访问内置插件

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]};

module.exports = config;

4.2 核心知识

原理剖析:

webpack 插件是一个具有 apply 属性的 JavaScript 对象。apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问

用法:

由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins 属性传入 new 实例。

配置:

// webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');

const config = {
  entry: './path/leo/file.js',
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

5. 模式

通过配置 mode 参数,指定当前的开发模式,有 development 和 production 两个值:

module.exports = {
  mode: 'production'
};

也可以通过 CLI 参数传递:

webpack --mode=production

参数描述:

选项 描述
development 会将 process.env.NODE_ENV 的值设为development。启用 NamedChunksPlugin和 NamedModulesPlugin
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPlugin,OccurrenceOrderPluginSideEffectsFlagPlugin 和 UglifyJsPlugin

记住,只设置 NODE_ENV,则不会自动设置 mode。

二. 配置

webpack 的配置文件,是导出一个对象的 JavaScript 文件,由 webpack 根据对象定义的属性进行解析。

因为 webpack 配置是标准的 Node.js CommonJS 模块,你可以做到以下事情:

  • 通过 require(...) 导入其他文件;
  • 通过 require(...) 使用 npm 的工具函数;
  • 使用 JavaScript 控制流表达式,例如 ?: 操作符;
  • 对常用值使用常量或变量;
  • 编写并执行函数来生成部分配置;

但应避免以下做法:

  • 在使用 webpack 命令行接口(CLI)(应该编写自己的命令行接口(CLI),或使用 --env)时,访问命令行接口(CLI)参数;
  • 导出不确定的值(调用 webpack 两次应该产生同样的输出文件);
  • 编写很长的配置(应该将配置拆分为多个文件);

1. 基本配置

// webpack.config.js

var path = require('path');
module.exports = {
  mode: 'development',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};

2. 多种配置

除了到处单个配置对象,我们也可以有一些其他方式:

2.1 导出为一个函数

我们可能需要同时考虑到开发环境生产环境,在 webpack.config.js中实现,我们会有至少两种方式:

  • 导出一个配置对象来代替;
  • 导出一个可以传入参数的函数:

传入两个参数:环境变量(查看 CLI 文档的环境选项)和 map 对象(argv)参数。

module.exports = function(env, argv) {
  return {
    mode: env.production ? 'production' : 'development',
    devtool: env.production ? 'source-maps' : 'eval',
    plugins: [
      new webpack.optimize.UglifyJsPlugin({
        compress: argv['optimize-minimize'] // 只有传入 -p 或 --optimize-minimize
       })
     ]
  };
};

2.2 导出为一个 Promise

webpack 将运行由配置文件导出的函数,并且等待 Promise 返回。便于需要异步地加载所需的配置变量。

module.exports = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve({
        entry: './app.js',
        /* ... */
      })
    }, 5000)
  })
}

2.3 导出多个配置对象

我们把导出对象设置成一个数组,webpack 运行时,会将所有配置对象都构建,这对于针对多个构建目标(例如 AMD 和 CommonJS)打包一个 library非常有用。

module.exports = [{
  output: {
    filename: './dist-amd.js',
    libraryTarget: 'amd'
  },
  entry: './app.js',
  mode: 'production',
}, {
  output: {
    filename: './dist-commonjs.js',
    libraryTarget: 'commonjs'
  },
  entry: './app.js',
  mode: 'production',
}]

3. 使用其他配置语言

webpack 接受以多种编程和数据语言编写的配置文件。支持的文件扩展名列表,可以在 node-interpret 包中找到。使用 node-interpret,webpack 可以处理许多不同类型的配置文件。

文档介绍:《使用不同语言进行配置(configuration languages)》

3.1 TypeScript

为了用 TypeScript 书写 webpack 的配置文件,必须先安装相关依赖:

npm install --save-dev typescript ts-node @types/node @types/webpack

使用 TypeScript 书写 webpack 的配置文件:

// webpack.config.ts

import path from 'path';
import webpack from 'webpack';

const config: webpack.Configuration = {
  mode: 'production',
  entry: './foo.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'foo.bundle.js'
  }
};
export default config;

3.2 Babel and JSX

在以下的例子中,使用了 JSXReact 形式的 javascript)以及 Babel 来创建 JSON 形式的 webpack 配置文件:

首先安装依赖:

npm install --save-dev babel-register jsxobj babel-preset-es2015

设置配置:

// .babelrc

{
  "presets": [ "es2015" ]
}
// webpack.config.babel.js

import jsxobj from 'jsxobj';

// example of an imported plugin
const CustomPlugin = config => ({
  ...config,
  name: 'custom-plugin'
});

export default (

);

三. 模块

1. 模块介绍

开发中将程序分解成离散功能块,成为模块。

而 webpack 模块能够以各种形式表达他们的依赖关系:

  • es6: import语句;
  • CommonJSrequire() 语句;
  • AMD: define 和 require 语句;
  • css/sass/less 文件中的 @import 语句;
  • 样式(url(...))或 HTML 文件中的图片链接(image url);

查看更多 模块方法

2. 模块解析

使用 resolver 库来找到模块的绝对路径,帮助 webpack 找到 bundle 中需要引入的模块代码,这些代码包含在每个 require / import 语句中,在模块打包中,webpack 使用 enhanced-resolve 来解析文件路径

webpack 解析规则: 使用 enhanced-resolvewebpack 支持解析三种文件路径:

  • 绝对路径:
import "/home/me/file";

import "C:\\Users\\me\\file";
  • 相对路径:
import "../src/file1";
import "./file2";
  • 模块路径:
import "module";
import "module/lib/file";

模块将在 resolve.modules 中指定的所有目录中搜索,另外可以使用 resolve.alias 做初始化模块路径。

解析器(resolver)检查路径是否指向文件或目录,如果是指向文件:

  • 如果有文件拓展名则直接打包;
  • 否则使用 [resolve.extensions] 选项作为文件扩展名来解析,配置解析器在解析中能够接受哪些扩展名(例如 .js.jsx)。

如果是指向文件夹,则按照步骤找到正确拓展名的文件:

  • 如果文件夹中包含 package.json 文件,则按照顺序查找 resolve.mainFields 配置选项中指定的字段。并且 package.json 中的第一个这样的字段确定文件路径。
  • 如果不存在 package.json 文件或者 package.json 文件中的 main 字段没有返回一个有效路径,则按照顺序查找 resolve.mainFiles 配置选项中指定的文件名,看是否能在 import/require 目录下匹配到一个存在的文件名。
  • 文件扩展名通过 resolve.extensions 选项采用类似的方法进行解析。

3. 解析 loader

Loader 解析遵循与文件解析器指定的规则相同的规则。但是 resolveLoader 配置选项可以用来为 Loader 提供独立的解析规则。

4. 缓存

每个文件系统访问都被缓存,以便更快触发对同一文件的多个并行或串行请求。在观察模式下,只有修改过的文件会从缓存中摘出。如果关闭观察模式,在每次编译前清理缓存。

有关上述配置的更多信息,请查看解析 API学习。

四. 构建目标

注意:webpack 的 target 属性不要和output.libraryTarget属性混淆。

1. 用法

在你的 webpack 配置中设置 target 的值:

module.exports = {
  target: 'node'
};

在上面例子中,使用 node webpack 会编译为用于「类 Node.js」环境(使用 Node.js 的 require ,而不是使用任意内置模块(如 fs 或 path)来加载 chunk)。

更多详细的值,可以参考 构建目标(targets)

2. 多个 target

尽管 webpack 不支持向 target 传入多个字符串,你可以通过打包两份分离的配置来创建同构的库:

var path = require('path');
var serverConfig = {
  target: 'node',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.node.js'
  }
  //…
};

var clientConfig = {
  target: 'web', // <=== 默认是 'web',可省略
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'lib.js'
  }
  //…
};

module.exports = [ serverConfig, clientConfig ];

到此这篇关于Webpack核心概念的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • webpack-dev-server核心概念案例详解

    webpack-dev-server 核心概念 Webpack 的 ContentBase vs publicPath vs output.path webpack-dev-server 会使用当前的路径作为请求的资源路径(所谓 当前的路径 就是运行 webpack-dev-server 这个命令的路径,如果对 webpack-dev-server 进行了包装,比如 wcf,那么当前路径指的就是运行 wcf命令的路径,一般是项目的根路径),但是读者可以通过指定 content-base 来修改这

  • Webpack框架核心概念(知识点整理)

    webpack是什么 webpack是一个前端构建的打包工具(并不是什么库或框架), 它能把各种资源,例如JS(含JSX).coffee.css(含less/sass).图片等都作为模块来处理和使用. 1.基础知识点 1.1 webpack 是一个现代 JavaScript 应用程序的模块打包器(module bundler).当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个

  • 浅谈Webpack核心模块tapable解析

    本文介绍了Webpack核心模块tapable,分享给大家,具体如下: 前言 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器,是对前端项目实现自动化和优化必不可少的工具,Webpack 的 loader (加载器)和 plugin (插件)是由 Webpack 开发者和社区开发者共同贡献的,而目前又没有比较系统的开发文档,想写加载器和插件必须要懂 Webpack 的原理,即看懂 Webpack 的源码, tapable 则是 Webpack 依赖的核心库,可以说不懂

  • 浅谈webpack 四个核心概念之Entry

    因为webpack是基于nodejs的一款工具,所以在学习过程中涉及到的nodejs知识也会进行解释进行发散性拓展. webpack中文文档 一.module.exports module.exports = { entry: './path/to/my/entry/file.js' }; exports 变量是在模块的文件级作用域内可用的,且在模块执行之前赋值给 module.exports在nodejs中,提供了exports 和 require 两个对象,其中 exports 是模块公开的

  • Webpack4.x的四个核心概念介绍

    目录 一. 概念 1. 入口 1.1 基础概念 1.2 单文件入口 1.3 多文件入口 2. 出口 2.1 基础概念 2.2 使用占位符来为每个文件命名,保证名称唯一 2.3 使用CDN和资源hash 3. loader 3.1 基础概念 3.2 安装并使用loader 3.3 使用loader的三种方式 3.4 loader加载顺序 3.5 loader 特性 4. 插件 4.1 基础概念 4.2 核心知识 5. 模式 二. 配置 1. 基本配置 2. 多种配置 2.1 导出为一个函数 2.2

  • JMM核心概念之Happens-before原则

    目录 一.前言 二.JMM 设计者的难题与完美的解决方案 三.8 条 Happens-before 规则 四."时间上的先发生" 与 "先行发生" 五.Happens-before 与 as-if-serial 一.前言 关于 Happens-before,<Java 并发编程的艺术>书中是这样介绍的: Happens-before 是 JMM 最核心的概念.对应 Java 程序员来说,理解 Happens-before 是理解 JMM 的关键. <

  • ZooKeeper分布式协调服务设计核心概念及安装配置

    目录 一.ZooKeeper 简介 1.ZooKeeper 设计目标 2.核心概念 1)Session 会话 2)数据节点 3)Watcher 4)ACL 3.Zab 协议介绍 二.ZooKeeper Cluster 安装 1.安装 ZooKeeper 2.使用 Golang 连接 ZooKeeper 的 API 接口 3.配置 ZooKeeper Cluster 一.ZooKeeper 简介 ZooKeeper 是一个开源的分布式协调服务,目前由 Apache 进行维护.ZooKeeper 可

  • Spring基础之AOP的概念介绍

    目录 前言 Spring的AOP的功能和目标 代理方式 @AspectJ的支持 启用@AspectJ 通过Java注解启用AspectJ注解支持: 通过XML配置启用AspectJ注解 定义一个切面 声明一个切入点 常见的切入点匹配表达 切面的增强 前增强BeforeAdvice 后增强 异常增强 环绕增强 代理机制 代理工厂的使用 Spring容器包含两个重要的特性:面向切面编程(AOP)和控制反转(IOC).面向切面编程是面向对象(OOP)的一种补充,在面向对象编程的过程中编程针对的目标是一

  • C#中委托的基本概念介绍

    最近在看深入理解C#,发现这是一本很不错的书,将很多C#的知识点联系了起来,更像是一本C#历史书,从C# 1一步步介绍到C# 4. 所以准备一边看,一边整理读书笔记.那么就先从委托开始. 委托是C#中一个非常重要的概念,从C# 1开始就有了委托这个核心概念,在C# 2和C# 3中委托又有了很多改进. 通过委托,我们可以将一个方法当作对象封装起来,并且在运行时,我们可以通过这个对象来完成方法的调用. 委托的使用 首先,来个简单的例子,苹果只负责设计iphone,而把组装iphone的工作委托给富士

  • vue组件三大核心概念图文详解

    前言 本文主要介绍属性.事件和插槽这三个vue基础概念.使用方法及其容易被忽略的一些重要细节.如果你阅读别人写的组件,也可以从这三个部分展开,它们可以帮助你快速了解一个组件的所有功能. 本文的代码请猛戳 github博客 ,纸上得来终觉浅,大家动手多敲敲代码! 一.属性 1.自定义属性props prop 定义了这个组件有哪些可配置的属性,组件的核心功能也都是它来确定的.写通用组件时,props 最好用对象的写法,这样可以针对每个属性设置类型.默认值或自定义校验属性的值,这点在组件开发中很重要,

  • ZooKeeper入门教程一简介与核心概念

    目录 1.ZooKeeper介绍与核心概念 1.1 简介 1.2分布式系统面临的问题 1.通过网络进行信息共享 2.通过共享存储 1.3 ZooKeeper如何解决分布式系统面临的问题 1.4 zookeeper概念介绍 1.4.1 znode 1.4.2 观察与通知 1.4.3 版本 1.4.4 法定人数 1.4.5 会话 1.4.6 会话状态和生命周期 回顾总结 本章是后续学习的基石,只有充分理解了分布式系统的概念和面临的问题,以及ZooKeeper内部的概念,才能懂得ZooKeeper是如

随机推荐