webpack基本概念

一、概述

本文将简单介绍webpack的基本用途以及它的四个基本概念Entry(入口文件)、Loader(加载器)、Output(输出文件)和Plugins(插件)。

  1. Webpack

    是一个Javascript程序的静态资源打包器, 递归地分析文件并建立一个依赖关系图, 然后把所有模块和他们的依赖打包进一个或者多个文件中, 它是高度可配置的,下面是它的四个核心概念。

  2. Entry(入口文件)

    指定了webpack该从那个文件开始去分析和建立依赖关系, webpack可找出文件的直接依赖和间接依赖。每个依赖会被打包进一个成为bundle的文件中。我们可以通过设置配置文件中的entry属性来指定一个或者多个Entry(入口文件)。

    webpack.config.js

module.exports = {
  entry: './path/to/my/entry/file.js'
};
  1. Output(输出文件)

    output属性规定了webpack该在哪里存放它打包好的bundle文件, 以及规定这些文件的的命名。

    webpack.config.js
const path = require('path');
module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
     path: path.resolve(__dirname, 'dist'),
     filename: 'my-first-webpack.bundle.js'
}
};
  1. Loaders(加载器)

    Loaders使webpack能够处理除了Javascript之外的文件(如css), webpack本身只支持处理Javascript文件, loaders能将特殊的文件转化为webpack能够处理的有效的模块(通过module选项)。

    在webpack配置文件中, loaders主要有两方面的配置:
  • 指定哪些类型的文件应该由对应的loader来处理(通过test属性正则匹配文件)

  • 转换这些文件使之能够被添加到依赖图中(use属性)

    webpack.config.js

    const path = require('path');
    const config = {
      entry: './path/to/my/entry/file.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
      },
      module: {
        rules:
        [
          { test: /.txt$/, use: 'raw-loader' }
        ]
      }
    };
    
    module.exports = config;
    

    上述配置中使用了包含两个必要子属性testuse的rules属性, 规定了 当webpack遇到.txt文件时, 先使用raw-loader进行转换, 再打包到bundle文件中。注意上述rules是在module下定义的。

  1. Plugins(插件)

    loaders用来处理特定的文件, 而plugins可以用来执行更广泛、更复杂的任务。plugins的能力范围从优化、压缩到定义environment-like的变量。plugins接口是非常强大的。

    为了使用插件, 必须使用require()方法引入它, 并把它加入到plugins数组中, 大多数插件可以通过指定选项来进行自定义配置。由于你可以在一个配置文件中多次使用同一类型的插件用作不同的目的, 所以你使用插件之前需要使用new操作符创建它的实例对象。

    webpack.config.js
  const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过npm  安装的插件
  const webpack = require('webpack'); //访问内置插件
  const path = require('path');
  
  const config = {
    entry: './path/to/my/entry/file.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'my-first-webpack.bundle.js'
    },
    module: {
      rules: [
        { test: /\.txt$/, use: 'raw-loader' }
      ]
    },
    plugins: [
      new webpack.optimize.UglifyJsPlugin(),
      new HtmlWebpackPlugin({template: './src/index.html'})
    ]
  };
  
  module.exports = config;

二、Entry Points(入口文件)

有许多方法可以在配置文件中定义Entry Points

单入口(简写)语法

用法: entry: string|Array<string>

webpack.config.js

const config = {
  entry: './path/to/my/entry/file.js'
};
module.exports = config;

它是以下配置的简写:

webpack.config.js

const config = {
  entry: {
    main: './path/to/my/entry/file.js'
  }
};
module.exports = config;

若使用数组, 那就变成了多入口文件配置。

对象语法

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

webpack.config.js

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

这种方式是最灵活的, 可伸缩的。Scalable webpack configurations/可伸缩webpack配置 指的是可重用的,并且可以与其他局部配置文件进行合并的配置。这是一个流行的技术用来分离不同的环境或运行时的配置文件, 然后通过webpack-merge等工具进行配置的整合。

应用场景

下面是一些有关entry配置的真实用例

1. 分离应用程序(app)和第三方库(vendor) 入口

webpack.config.js

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

这是什么?

从表面上看,这告诉我们 webpack 从 app.js 和 vendors.js 开始创建依赖图(dependency graph)。这些依赖图是彼此完全分离、互相独立的(每个 bundle 中都有一个 webpack 引导(bootstrap))。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程序(single page application)中。

为什么?

此设置允许你使用 CommonsChunkPlugin 从「应用程序 bundle」中提取 vendor 引用(vendor reference) 到 vendor bundle,并把引用 vendor 的部分替换为 webpack_require() 调用。如果应用程序 bundle 中没有 vendor 代码,那么你可以在 webpack 中实现被称为长效缓存的通用模式。

2. 多页面应用程序

webpack.config.js

const config = {
  entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
};

这是什么?

告诉 webpack 需要 3 个独立分离的依赖图(如上面的示例)

为什么?

在多页应用中,每当页面跳转时,服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。然而,这给了我们特殊的机会去做很多事:

  • 使用 CommonsChunkPlugin 为每个页面间的应用程序共享代码创建 bundle。由于入口起点增多,多页应用能够复用入口起点之间的大量代码/模块,从而可以极大地从这些技术中受益

根据经验:每个 HTML 文档应该只使用一个入口文件

三、Loaders(加载器)

Loader用于对模块的源代码进行转换。 loader可以使你在import或"加载"模块时预处理文件。 因此,loader类似于其他构建工具中"任务(task)", 并提供了处理前端构建步骤的强大方法。 loader可以将文件从不同的语言(如TypeScript)转换为 JavaScript, 或将内联图像转换为DataURL。 loader甚至允许你直接在JavaScript模块中importCSS文件

例子

如果要求webpack处理css和Typescript文件, 首先需要从npm安装对应的loader

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

然后在配置文件中进行设置

webpack.config.js

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

loaders使用方式

  1. Configuration(推荐): 在配置文件中进行配置
  2. Inline: 在每个import语句中额外指明所使用的loader
  3. CLI: 在Shell命令中指定loader

1. Configuration方式配置

module.rules允许你在webpack配置中指定多个loader。 这是展示loader的一种简明方式, 并且有助于使代码变得简洁。 同时让你对各个loader有个全局概览

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        { loader: ['style-loader'](/loaders/style-loader) },
        {
          loader: ['css-loader'](/loaders/css-loader),
          options: {
            modules: true
          }
        }
      ]
    }
  ]
}

2. Inline方式配置

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

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

这可以覆盖Configuration中的loader设置,并且可以?进行传参参数可以使JSON对象

3. CLI方式配置

命令行示例

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

上述命令使用对.jade文件使用jade-loader, 对css文件使用style-loadercss-loader

任何情况下,都应该尽量使用配置文件的方式来配置loader

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 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译和其他更多。

四、Output(输出文件)

配置output选项可以控制webpack如何向硬盘写入编译文件。注意, 虽然可以存在多个入口文件, 但只能指定一个输出配置

用法

设置output的最低需求是在配置文件的output属性值中指定以下两个选项:

  • filename: 输出文件的文件名
  • path: 输出文件的绝对路径

webpack.config.js

const config = {
  output: {
    filename: 'bundle.js',
    path: '/home/proj/public/assets'
  }
};
module.exports = config;

该配置会在/home/proj/public/assets中生成bundle.js文件

多入口文件配置

如果配置创建了多个单独的"chunk"(例如,使用多个入口文件或使用像CommonsChunkPlugin这样的插件), 则应该使用占位符(substitutions)来确保每个文件具有唯一的名称。

{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}

// 写入磁盘: ./dist/app.js, ./dist/search.js

高级用法

CDN上使用资源Hash

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

在编译时不知道最终输出文件的publicPath的情况下,publicPath可以留空, 并且在入口起点文件运行时使用__webpack_public_path__动态设置

__webpack_public_path__ = myRuntimePublicPath

// 剩余的应用程序入口

五、Plugins(插件)

插件是webpack中的支柱功能, webpack本身也是构建于同一套插件系统之上, 插件是为了解决loader无法解决的事情

剖析

webpack插件是一个具有apply方法的javascript对象。 这个applywebpack compiler调用, 从而使插件获得对webpack编译的整个生命周期的访问能力

ConsoleLogOnBuildWebpackPlugin.js

function ConsoleLogOnBuildWebpackPlugin() {

};

ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) {
  compiler.plugin('run', function(compiler, callback) {
    console.log("The webpack build process is starting!!!");

    callback();
  });
};

用法

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

根据使用webpack的方式,插件也有多种使用方式

Configuration方式使用

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');

const config = {
  entry: './path/to/my/entry/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;

Node API方式使用

即便使用 Node API,用户也应该在配置文件中配置插件, compiler.apply 并不是推荐的使用方式

some-node-script.js

const webpack = require('webpack'); //访问 webpack 运行时(runtime)
const configuration = require('./webpack.config.js');

let compiler = webpack(configuration);
compiler.apply(new webpack.ProgressPlugin());

compiler.run(function(err, stats) {
  // ...
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343