Appearance
webpack
webpack所解决的问题:
如何在前端项目中更高效的管理和维护项目中的每一个资源
模块化
模块化的演进过程
早期的前端技术标准根本没有预料到前端行业会有今天这个规模,所以在设计上存在很多缺陷
Stag1 - 文件划分的方式
缺点:
- 模块直接在全局工作,大量模块成员污染全局作用域
- 没有私有空间,所有模块内的成员都可以在模块外部被访问和修改
- 一旦模块增多,容易产生命名冲突
- 无法管理模块与模块之间的依赖
- 在维护的过程中也很难分辨每个成员所属的模块
Stag2 - 命名空间方式
解决了命名冲突的问题,但其他问题依然存在
Stag3 - IIFE
以上方式有模块加载的问题
更为理想的方式是在页面中引入一个JS入口文件,其余用到的模块可以通过代码控制,按需加载
模块化规范的出现
目前通过约定实现模块化的方式,不同的开发者在实施的过程中会出现一些细微的差别,为了统一不同开发者、不同项目之间的差异,就需要制定一个行业标准去规范模块化的实现方式
两点需求:
- 一个统一的模块化标准规范
- 一个可以自动加载模块的基础库
CommonJS规范
是Node.js中所遵循的模块规范
该规范约定一个文件就是一个模块,每个模块都有单独的作用域,通过module.exports导出成员,再通过require函数载入模块
AMD规范
在早期制定前端模块化标准时,并没有直接选择CommonJS规范,而是专门为浏览器重新设计了一个规范AMD(Asynchronous Module Definition),即异步模块定义规范
同期还推出了Require.js,除了实现了AMD模块化规范,本身也是一个非常强大的模块加载器
ES Modules规范
JavaScript的标准逐渐走向完善
端模块化规范的最佳实践方式也基本实现了统一:
- 在Node.js环境中,遵循CommonJS规范来组织模块
- 在浏览器环境中,遵循ES Modules规范
ES modules规范是ECMAScript 2015(ES6) 中才定义的模块系统,是近几年才制定的标准,存在环境兼容问题,随着Webpack等一系列打包工具的流行,这一规范才开始逐渐被普及
经过5年的迭代,ESModules已发展成为现今最主流的前端模块化标准
针对ES Modules本身的一些特性可参考:
- MDN官方的详细资料
- ECMAScript官方详细资料
模块化问题
我们所使用的 ES Modules模块系统本身就存在环境兼容问题,尽管现如今主流浏览器的最新版本都支持这一特性,是目前还无法保持用户的浏览器使用情况,所以还需要解决兼容问题
模块化的方式划分出来的模块文件过多,而前端应用又运行在浏览器中,每一个文件都需要单独从服务端请求回来,零散的模块文件必然导致浏览器的频繁发送网络请求,影响应用的工作效率
随着应用日益复杂,在前端应用开发过程中不仅仅只有JavaScript代码需要模块化,HTML和CSS这些资源文件也会面临需要被模块化的问题,从宏观角度来看,这些文件也都应该看作前端应用中的一个模块,只不过这些模块的种类和用途跟JavaScript不同
Webpack从一个“打包工具”发展成现在开发者眼中对整个前端项目的“构建系统”,表面上似乎只是称呼发生了变化,但背后却透露出一个信号:模块化思想是非常伟大的,伟大到可以帮你“统治”前端整个项目
如何使用Webpack实现模块化打包?
- 能够将散落的模块打包到一起
- 能够编译代码中的新特性
- 能够支持不同种类的前端资源模块
以Webpack为例:
- Webpack作为一个模块打包工具,本身就可以实现模块化代码打包的问题,通过Webpack可以将零散的JavaScript代码打包到一个JS文件中
- 对于有环境兼容问题的代码,Webpack可以在打包过程中通过Loader机制对其实现编译转换,然后再进行打包
- 对于不同类型的前端模块,Webpack支持在JavaScript中以模块化的方式载入任意类型的资源文件,例如可以通过Webpack实现在JavaScript中加载CSS文件,被加载的CSS文件将会通过style标签的方式工作
Webpack还具有代码拆分的能力,能够将应用中所有的模块按需分块打包,不用担心全部代码打包到一起,产生单个文件过大,导致加载慢的问题,非常适合现代化的大型Web应用
作为目前最主流的前端模块打包器,提供了一整套前端项目模块化方案,而不仅仅局限于对JavaScript的模块化,可以轻松实现对前端项目开发过程中涉及到的资源进行模块化
快速上手
bash
# 安装
npm i webpack webpack-cli --save-dev
# 查看版本
npx webpack --version
# 执行: 默认会自动从src/index.js文件开始打包
webpack配置打包过程
js
// webpack.config.js
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'output')
}
}Webpack的配置项较多,很多选项都支持不同类型的配置方式,如果你刚刚接触Webpack的配置,这些配置选项一定会让你感到头大
Webpack针对不同环境的三组预设配置:
production模式 启动内置优化插件,自动优化打包结果,打包速度偏慢
development模式 自动优化打包速度,添加一些调试过程中的辅助插件以便于更好的调试错误
none模式 运行最原始的打包,不做任何额外处理,这种模式一般需要分析我们模块的打包结果时会用到
想要修改Webpack工作模式的方式有两种:
- 通过CLI --mode 参数传入
- 通过配置文件设置mode属性
如何通过Loader实现特殊资源加载?
Webpack不仅是JavaScript模块打包工具,还是整个前端项目(前端工程)的模块打包工具,可以通过Webpack去管理前端项目中任意类型的资源文件
使用Loader
js
// webpack.config.js
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.md$/,
use: './markdown-loader'
}
]
}
}实现Loader
js
// markdown-loader.js
const { marked } = require('marked')
module.exports = source => {
// 1
// 加载到的模块内容
// console.log(source);
// 返回值就是最终被打包的内容
// return 'hello loader~'
// return 'console.log("hello loader~")'
// 2
// 将markdown转换为html字符串
const html = marked.parse(source)
console.log(html)
// 将html字符串拼接为一段导出字符串的JS代码
// // const code = `module.exports = ${JSON.stringify(html)}`
// const code = `exports default ${JSON.stringify(html)}`
// // 返回js代码
// return code
// 3
// 直接返回html,交给下一个loader去处理
return html
}Loader机制是Webpack最核心的机制,正因为有Loader机制,Webpack才能足以支撑整个前端项目模块化的大梁,实现通过Webpack去加载任何你想要加载的资源
Webpack 插件机制的目的
是为了增强Webpack在项目自动化构建方面的能力
插件最常见的应用场景:
- 实现自动在打包之前清除dist目录(上次的打包结果)
- 自动生成应用所需要的HTML文件
- 根据不同环境为代码注入类似API地址这种可能变化的部分
- 拷贝不需要参与打包的资源文件到输出目录
- 压缩Webpack打包完成后输出的文件
- 自动发布打包结果到服务器实现自动部署
常用插件
- clean-webpack-plugin
实现自动在打包之前清除dist目录
npm i clean-webpack-plugin -D
- html-webpack-plugin
用于生成HTML的插件
npm i html-webpack-plugin -D
HTML文件一般都是通过硬编码的方式,单独存放在项目目录下
这种方式有两个问题:
- 项目发布时,我们需要同时发布根目录下的HTML文件和dist目录中所有的打包结果,非常麻烦,而且上线过后还要确保HTML代码中的资源文件路径是正确的
- 如果打包结果输出的目录或者文件名称发生变化,那HTML代码中所对应的script标签也需要我们手动修改路径
相比于之前写死HTML文件的方式,自动生成HTML的优势在于:
- HTML也输出到dist目录中了,上线时只需要把dist目录发布出去
- HTML中的script标签是自动引入的,所以可以确保资源文件的路径是正常的
webpack 构建TS项目
安装依赖
安装webpack npm install webpack -D
webpack4以上需要 npm install webpack-cli -D
编译TS npm install ts-loader -D
TS环境 npm install typescript -D
热更新服务 npm install webpack-dev-server -D
HTML模板 npm install html-webpack-plugin -D配置文件
js
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: "./src/index.ts",
mode: "development",
output: {
path: path.resolve(__dirname, './dist'),
filename: "index.js"
},
stats: "none",
resolve: {
extensions: ['.ts', '.js'],
alias: {
'@': path.resolve(__dirname, './src')
}
},
module: {
rules: [
{
test: /\.ts$/,
use: "ts-loader"
}
]
},
devServer: {
port: 1988,
proxy: {}
},
plugins: [
new htmlWebpackPlugin({
template: "./public/index.html"
})
]
}