webpack入门


webpack 简述

按照webapck 官网所说,webpack 是一个模块打包工具(webpack is a module bundler)。它接收依赖的模块,将其转化为静态资源。

webpack 与众不同的三大核心概念

  1. Code Spliting

  2. Loaders

  3. Plugin System

配置(configuration)

CLI

如果使用 CLI,webpack 将会读取 webpack.config.js 文件(或者通过–config 选项传递的文件),这个文件需要暴露这样的配置对象:

module.exports = {
  // configuration
};

常见 CLI option

1)开发环境简写 -d

等价于:–debug –devtool source-map –output-pathinfo

2)生产环境简写 -p

等价于:–optimize-minimize –optimize-occurrence-order

3)监视模式 –watch

4)配置文件 –config example.config.js

指定新的配置文件,而不是默认的 webpack.config.js

5)常见的显示选项

  • –progress

  • –display-chunks

  • –display-reasons

  • –display-error-details

  • –display-modules

  • –display-exclude

可以通过 script 来定义脚本,然后 npm run 命令名。

** 一个简单的配置对象,注意不是 json,只是简单的 object **

{
		context: __dirname + "/app",
		entry: "./entry",
		output: {
				path: __dirname + "/dist",
				filename: "bundle.js"
		}
}

context

context:根目录(绝对路径!)。可以认为是文件查找的上下文。默认 process.cwd()

entry

entry:包的入口点,有三种形式

  1. 一个 string

  2. 一个由多个 string 构成的 array

  3. 一个 object(多页面场景下),key 是 chunk 的 name,value 可以是 string 或者 array

output

output.filename

不要在这里指定绝对路径

多入口情况下使用占位符

  • [name] 模块名称

  • [hash] 模块编译后的(整体)Hash 值

  • [chunkhash] 分片的 Hash 值,可以认为是文件的版本号,也可以认为是文件的 MD5 值,在静态资源的版本管理中非常有用

output.path

output.publicPath

指定 public URL 地址,当我们要将 output 的文件放在不同的域名或者 CDN 上时十分有用

module

module.loaders 一个自动应用的 loaders 的数组,每项(item)可以有这些属性:

  • test: A condition that must be met

  • exclude: A condition that must not be met

  • include: An array of paths or files where the imported files will be transformed by the loader

  • loader: A string of “!” separated loaders

  • loaders: An array of loaders as string

resolve

resolve.alias

模块别名定义,方便后续直接引用别名

resolve: {
	alias: { AppStore : 'js/stores/AppStores.js',//之后直接 require('AppStore')
	}
}

resolve.root

包含你模块的目录(绝对路径),也可以是一个目录数组,这个设置应该被用于添加个人目录到 webpack 查找路径里

必须是个绝对路径,不要这样写./app/modules

resolve.modulesDirectories

这是一个目录数组,用来解析到当前目录以及祖先目录和查找模块。这个函数的工作原理和 node 如何查找 node_modules 目录很像。比如如果值为[“mydir”],webpack 会查找“./mydir”, “../mydir”, “../../mydir”等等

默认: [“web_modules”, “node_modules”]

resolve.extensions

一个用来解析模块的拓展名数组。比如,为了发现一个 CoffeeScript 文件,你的数组里应该包含字符串”.coffee”

默认: [“”, “.webpack.js”, “.web.js”, “.js”]

注意:设置这个选项将会重写默认值

externals

指定不该被 webpack 打包的模块,但是在打包后的包中仍然保留了请求。

我们可以通过它来暴露全局变量,而在需要的文件中直接 require 或 import 就可以了

externals: {
  jquery: 'jQuery';
}

plugins

给编译器添加额外的插件

各种 loaders

webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。你可以使用 Node.js 来很简单地编写自己的 loader。

loader 的使用有三种方法,分别是:

  • 在 require 中显式指定,即上面看到的用法

  • 在配置项(webpack.config.js)中指定

  • 在命令行中指定

    1)babel-loader

转换 ES6 语法或 React 语法

通过 presets 选择 ES6 特性,也可以在 package.json 中指定

解决 babel-loader 处理 React 的 preset 问题:npm i –save-dev babel-preset-react

2)css 相关

  • style-loader 将模块的导出作为样式添加到 DOM 中

  • css-loader 解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码,可以在 loader 后面?modules 以支持CSS Module

  • less-loader 加载和转译 LESS 文件

  • sass-loader 加载和转译 SASS/SCSS 文件,须先安装 node-sass,windows 可能安装出错,使用 cnpm i node-sass –save-dev 或者如下:

    npm install –save-dev node-sass –registry=https://registry.npm.taobao.org –disturl=https://npm.taobao.org/dist –sass-binary-site=http://npm.taobao.org/mirrors/node-sass

  • postcss-loader 使用 PostCSS 加载和转译 CSS/SSS 文件,可以进行 autoprefixer

CSS 中@import 另一个 CSS 怎么处理?(非 SASS、LESS)

给 css-loader 添加参数

loader: 'style-loader!css-loader?importLoaders=1!postcss-loader'

3)模板相关

  • html-loader 导出 HTML 为字符串,需要引用静态资源

  • jade-loader 加载 Jade 模板并返回一个函数

  • markdown-loader 将 Markdown 转译为 HTML

  • handlebars-loader 将 Handlebars 转换为 HTML

  • ejs-loader 将 underscore 模板转换为 HTML

    4)图片相关

  • file-loader

  • url-loader 与 file-loader,但如果文件小于限制,可以返回 data URL

  • image-loader 压缩图片

components 模板引用相对路径图片不会替换?

可以使用绝对路径或者这样写 src=”${require(‘../../assets/bg.png’)}”

5)bundle-loader

bundle-loader 是一个用来在运行时异步加载模块的 loader。可以用来做代码分割

6)exports-loader

可以从模块中导出变量。

在实际使用中,用 exports-loader 最多的场景是将某些不支持模块化规范的模块所声明的全局变量作为模块内容导出。
如下可以导出全局变量 Hello,exports-loader 还可以支持同时导出多个变量,例如 exports?HELLO,WORLD

module.exports = {
  module: {
    loaders: [{ test: require.resolve('./hello'), loader: 'exports?Hello' }],
  },
};

7)imports-loaders

用于向一个模块的作用域内注入变量(Can be used to inject variables into the scope of a module)

8)expose-loader

把一个模块导出并付给一个全局变量

require('expose?libraryName!./file.js');
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.

各种 plugins

1)HtmlWebpackPlugin

参数:

  • template html 模板地址,默认为 webpack.config.js 所在的目录

  • inject 插入位置

  • title

  • date 等

    2)CommonsChunkPlugin

将多个入口起点之间共享的公共模块,生成为一些 chunk,并且分离到单独的 bundle 中,例如,1vendor.bundle.js 和 app.bundle.js

3)ExtractTextWebpackPlugin

从 bundle 中提取文本(CSS)到分离的文件(app.bundle.css)

4)ProvidePlugin

ProvidePlugin 可以将模块作为一个变量,被 webpack 在其他每个模块中引用。只有你需要使用此变量的时候,这个模块才会被 require 进来。多数之前遗留的模块,会依赖于已存在的某些特定全局变量,比如 jQuery 插件中的$或者jQuery。在这种场景,你可以在每次遇到全局标识符$的时候,在 webpack 中预先设置 var $ = require(“jquery”)。

module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
    }),
  ],
};

Environment flags

windows 下使用 cross-env 的 npm 包兼容处理,可以在 package.json 设置如下:

"scripts": {
		"clear": "rm -rf build&& mkdir build",
		"start": "npm run clear&& cross-env NODE_ENV=development webpack-dev-server --host 0.0.0.0 --devtool eval --progress --color --profile",
		"deploy": "npm run clear&& cross-env NODE_ENV=production webpack -p --progress"
}

webpack.config.js

var isProduction = process.env.NODE_ENV === 'production';

plugins: [
  new webpack.DefinePlugin({
    'process.env': {
      NODE_ENV: JSON.stringify(process.env.NODE_ENV || 'development'),
    },
  }),
];

Code splitting(代码分割)

使用 require.ensure

// main.js
require.ensure(['./a'], function (require) {
  var content = require('./a');
  document.open();
  document.write('<h1>' + content + '</h1>');
  document.close();
});

// a.js
module.exports = 'Hello World';

require.ensure 告诉 Webpack,./a.js 应该从 bundle.js 分离并且打包成一个单独的文件

注意 require.ensure 只会加载模块而不会去解析

也可以用 bundle-loader 进行代码分割

// main.js

// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');

// To wait until a.js is available (and get the exports)
//  you need to async wait for it.
load(function (file) {
  document.open();
  document.write('<h1>' + file + '</h1>');
  document.close();
});

vendor chunk

可以用 CommonsChunkPlugin 插件将公共库(vendor)打包成一个单独的文件

var webpack = require('webpack');

module.exports = {
  entry: {
    app: './main.js',
    vendor: ['jquery'],
  },
  output: {
    filename: 'bundle.js',
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin(
      /* chunkName= */ 'vendor',
      /* filename= */ 'vendor.js'
    ),
  ],
};

模块热替换(Hot Module Replacement)

npm i webpack-dev-server --save-dev

配置

主要参考资料

webpack 官方文档

阮一峰 webpack 教程


文章作者: Angus
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Angus !
  目录