Webpack 是一个前端资源加载和打包工具。所谓的模块就是在平时的前端开发中,用到一些静态资源,如JavaScript、CSS、图片等文件,webpack就将这些静态资源文件称之为模块。 webpack支持AMD和CommonJS,以及其他的一些模块系统,并且兼容多种JS书写规范,可以处理模块间的依赖关系,所以具有更强大的JS模块化的功能,它能对静态资源进行统一的管理以及打包发布。 作为一款 Grunt和Gulp的替代产品,Webpack受到大多数开发者的喜爱,因为它能够编译打包CSS,做CSS预处理,对JS的方言进行编译,打包图片,代码压缩等等。
与其他的构建工具相比,Webpack具有如下的一些优势:
- 对 CommonJS 、 AMD 、ES6 的语法做了兼容;
- 对 js、css、图片等资源文件都支持打包;
- 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对 CoffeeScript、ES6的支持;
- 有独立的配置文件 webpack.config.js;
- 可以将代码切割成不同的 chunk,实现按需加载,降低了初始化时间;
- 支持 SourceUrls 和 SourceMaps,易于调试;
- 具有强大的 Plugin 接口,大多是内部插件,使用起来比较灵活;
- webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快。
在Webpack的世界里有两个最核心的概念: 1.一切皆模块 正如js文件可以是一个“模块(module)”一样,其他的(如css、image或html)文件也可视作模 块。因此,你可以require(‘myJSfile.js’)亦可以require(‘myCSSfile.css’)。这意味着我们可以将事物(业务)分割成更小的易于管理的片段,从而达到重复利用等的目的。
2.按需加载 传统的模块打包工具(module bundlers)最终将所有的模块编译生成一个庞大的bundle.js文件。但是在真实的app里边,“bundle.js”文件可能有10M到15M之大可能会导致应用一直处于加载中状态。因此Webpack使用许多特性来分割代码然后生成多个“bundle”文件,而且异步加载部分代码以实现按需加载。
Webpack安装webpack支持使用npm 或者 yarn 方式进行安装,当然也可以作为一个全局的命令来使用。
npm install webpack webpack-cli -g
# 或者
yarn global add webpack webpack-cli
webpack-cli 是 webpack 的命令行工具,在 4.x 版本之后不再作为 webpack 的默认依赖,我们可以在使用时单独安装这个工具。
通常,我们使用“npm init”命令来创建前端项目的时候,每个项目下都必须配置有一个 webpack.config.js通常放在项目的根目录中,它本身也是一个标准的Commonjs规范的模块。然后使用“npm install”命令来安装webpack,例如:
npm install webpack -D
# 或者
yarn add webpack -D
这样, package.json配置文件就会添加webpack相关的内容。例如:
"scripts": {
"build": "webpack --mode production"
},
"devDependencies": {
"webpack": "^4.1.1",
"webpack-cli": "^2.0.12",
}...
创建好之后执行 “npm run build” 或者 “yarn build” 命令,你就会发现新增了一个 dist 目录,里边存放的是 webpack 构建好的 main.js 文件。
因为是作为项目依赖进行安装,所以不会有全局的命令,npm/yarn 会帮助我们在当前项目依赖中寻找对应的命令执行,如果是全局安装的 webpack,直接执行 webpack –mode production 就可以。
Webpack基本概念Webpack 本质上是一个打包工具,它会根据代码的内容解析模块依赖,帮助我们把多个模块的代码打包。下面是Webpack官网给的一个说明图。 如上图,webpack 会把项目中使用到的多个代码模块(可以是不同文件类型),打包构建成项目运行仅需要的几个静态文件(如.js、.css等)。
每个应用程序都有自己的入口文件,而Webpack构建的项目的默认的入口文件就是“./src/index.js” 。
入口使用 entry 字段来进行配置,可以是个字符串或数组或者是对象;如果是数组,数组中的所有文件会打包生成一个filename文件;如果是对象,可以将不同的文件构建成不同的文件。例如:
module.exports = {
entry: './src/index.js'
}
// 上述配置等同于
module.exports = {
entry: {
main: './src/index.js'
}
}
// 或者配置多个入口
module.exports = {
entry: {
foo: './src/page-foo.js',
bar: './src/page-bar.js',
// ...
}
}
// 使用数组来对多个文件进行打包
module.exports = {
entry: {
main: [
'./src/foo.js',
'./src/bar.js'
]
}
}...
loader
webpack 中提供一种处理多种文件格式的机制,便是使用 loader。我们可以把 loader 理解为是一个转换器,负责把某种文件格式的内容转换成 webpack 可以支持打包的模块。
在webpack中JavaScript,CSS,LESS,TypeScript,JSX,CoffeeScript,图片等静态文件都是模块,不同模块的加载是通过模块加载器(webpack-loader)来统一管理的当我们需要使用不同的 loader 来解析处理不同类型的文件时,我们可以在 module.rules 字段下来配置相关的规则。例如使用 Babel 来处理 .js 文件。
module: {
// ...
rules: [
{
test: /\.jsx?/, // 匹配文件路径的正则表达式,通常我们都是匹配文件类型后缀
include: [
path.resolve(__dirname, 'src') // 指定哪些路径下的文件需要经过 loader 处理
],
use: 'babel-loader', // 指定使用的 loader
},
],
}...
loader 是 webpack 中比较复杂的一块内容,它支撑着 webpack 来处理文件的多样性。并且webpack 2.x 之后 module.loaders改成了module.rules。
plugin在 webpack 的构建流程中,plugin 用于处理更多其他的一些构建任务。可以这么理解,模块代码转换的工作由 loader 来处理,除此之外的其他任何工作都可以交由 plugin 来完成。
webpack提供了“丰富的组件”来满足我们不同的需求,当然也可以自行实现一个组件来满足特定的需求。在webpack中,可以通过 plugins 字段来添加新的 plugin 。例如:
//导入plugin
const UglifyPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new UglifyPlugin() //新的plugin
],
}
常用的插件有:
- HotModuleReplacementPlugin –开启全局的模块热替换(HMR);
- NamedModulesPlugin –当模块热替换(HMR)时在浏览器控制台输出对用户更友好的模块名字信息;
- CommonsChunkPlugin –提取chunk公共部分;
- ExtractTextPlugin –独立生成css文件,以外链的形式加载;
- UglifyJsPlugin –压缩js;
- HtmlWebpackPlugin –使用模版生成html。
理论上plugin可以干涉 webpack 的整个构建流程,可以在流程的每一个步骤中定制自己的构建需求。
输出webpack 的输出即指 webpack 最终构建出来的静态文件,即打包构建成项目运行仅需要的几个静态文件。输出使用output进行设置。
module.exports = {
// ...
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
}
// 或者多个入口生成不同文件
module.exports = {
entry: {
foo: './src/foo.js',
bar: './src/bar.js',
},
output: {
filename: '[name].js',
path: __dirname + '/dist',
},
}
// 路径中使用 hash,每次构建时会有一个不同 hash 值,避免发布新版本时线上使用浏览器缓存
module.exports = {
// ...
output: {
filename: '[name].js',
path: __dirname + '/dist/[hash]',
},
}...
resolve
webpack在构建包的时候会按目录的进行文件的查找,resolve属性中的extensions数组中用于配置程序可以自行补全哪些文件后缀。例如:
resolve: {
modules: [path.resolve(__dirname, "node_modules")]
extensions: ['', '.js', '.json', '.scss'],
//模块别名定义,方便后续直接引用别名,无须多写长长的地址
alias: {
AppStore : 'js/stores/AppStores.js',//后续直接 require('AppStore') 即可
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js'
}
}
webpack配置
下面是一个webpack.config.js的综合示例,当然,正式的项目的webpack.config.js配置远比这复杂的多。
const path = require('path')
const UglifyPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?/,
include: [
path.resolve(__dirname, 'src')
],
use: 'babel-loader',
},
],
},
// 代码模块路径解析的配置
resolve: {
modules: [
"node_modules",
path.resolve(__dirname, 'src')
],
extensions: [".wasm", ".mjs", ".js", ".json", ".jsx"],
},
plugins: [
new UglifyPlugin(),
// 使用 uglifyjs-webpack-plugin 来压缩 JS 代码
// 如果你留意了我们一开始直接使用 webpack 构建的结果,你会发现默认已经使用了 JS 代码压缩的插件
// 这其实也是我们命令中的 --mode production 的效果,后续的小节会介绍 webpack 的 mode 参数
],
}...
参考: 官网地址:https://webpack.js.org/ 中文官网:https://doc.webpack-china.org/ webpack简介与使用:https://segmentfault.com/n/1330000009501031