1.0 概念
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。
源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括如下内容:
代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。
代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力。
2.0 它如何工作的?
把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。和gulp功能类似,实现原理有差异,Webpack的处理速度更快更直接,能打包更多不同类型的文件。它的四个核心概念:入口(entry)、输出(output)、loader、插件(plugins)。
3.核心概念
3.1.入口
使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。webpack配置文件
中配置 entry
属性,来指定一个入口起点(或多个入口起点)。webpack.config.js 中配置入口:
- 单个入口简写法
//简写法
module.exports = {
entry: './path/to/my/entry/file.js'
};
- 对象语法
//上面简写的具体
module.exports = {
entry: {
main: './path/to/my/entry/file.js'
}
};
//多个入口
module.exports = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
- 场景应用场景
<1>分离 应用程序(app) 和 第三方库(vendor) 入口。
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
webpack 从 app.js 和 vendors.js 开始创建依赖图,这些依赖图是彼此完全分离、互相独立的。这种方式比较常见于,只有一个入口起点(不包括 vendor)的单页应用程序(single page application)中。
<2>多页面应用程序
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
webpack 需要 3 个独立分离的依赖图,在多页应用中,每当页面跳转时服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。
3.2. 出口
告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。通过在配置中指定一个 output 字段,来配置这些处理过程。
//Node.js 核心模块,用于操作文件路径
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
//__dirname表示当前文件所在的目录
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js'
}
};
(1)output.filename
此选项决定了每个输出 bundle 的名称。
- 对于单个入口起点,filename 会是一个静态名称,如:
filename: "bundle.js"
- 多个入口起点(entry point)
通过代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称,如:
//使用入口名称
filename: "[name].bundle.js"
//使用内部 chunk id
filename: "[id].bundle.js"
//使用每次构建过程中,唯一的 hash 生成
filename: "[name].[hash].bundle.js"
//使用基于每个 chunk 内容的 hash
filename: "[chunkhash].bundle.js"
3.3. loader
loader 用于对模块的源代码进行转换
, loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)。因此,loader 类似于其他构建工具中“任务(task)”
,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
在 webpack 的配置中 loader 有两个属性:
- test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
- use 属性,表示进行转换时,应该使用哪个 loader。
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module: {
rules: [
{ test: /\.css$/, use: 'css-loader' },
{ test: /\.ts$/, use: 'ts-loader' },
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
}
]
}
3.4.插件
oader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务
。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。详细用法:
你只需要 require() 它,然后把它添加到 plugins 数组中。
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
module: {
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;