前端工程化
小白 vs 实际的前端开发
- 小白眼中的前端开发
- 会写 HTML + CSS + JavaScript 就会前端开发
- 需要美化页面样式,就拽一个 bootstrap 过来
- 需要操作 DOM 或发起 Ajax 请求,就拽一个 jQuery 过来
- 需要渲染模板结构,就用 art-template 等引擎模板
- 实际的前端开发
- 模块化( js 模块化、css 模块化、其他资源的模块化)
- 组件化( 复用现有组件的 UI 结构、样式、行为)
- 规范化( 目录结构的划分、编码规范化、接口规范化、文档规范化、Git 分支管理)
- 自动化
- 在开发中,会将webpack的开发环境进行分离,抽出来分成三个
.js
文件,分别是:config
目录webpack.dev.config.js
—-> 开发环境webpack.prod.config.js
—-> 生产环境webpack.common.config.js
—-> 通用配置
- 抽离后需要将
webpack.common.config.js
文件分别导入开发和生产环境内- 安装:
npm install webpack-merge -D
- 导入:
const {merge} = require('webpack-merge')
const commonConfig = require('./webpack.common.config')
- 使用
module.exports = merge(commonConfig, {项目配置内容})
- 安装:
- 开发和生产环境的导入和使用方式相同
- 配置中有些路径需要修改,有些不需要
- 在开发中,会将webpack的开发环境进行分离,抽出来分成三个
webpack
// 局部安装 npm install webpack webpack-cli -D
<a name="P6aJV"></a>
## 使用webpack进行打包
```bash
$ webpack
# 方法1
$ ./node_modules/.bin/webpack
# 方法2
$ npx webpack
# 方法3
# 1. 在 package.json 文件中添加以下配置
"scripts": {
"build": "webpack"
}
# 2. 在命令行执行
$ npm run build
# 方法4:指定打包入口以及出口
$ npx webpack --entry ./src/main.js --output-path ./build
快速生成 package.json文件
# 方法1
npm init
# 方法2
npm init -y
mode 的可选值
- development
- 开发环境
- 不会对打包生成的文件进行代码压缩和性能优化
- 打包速度快,适合在开发阶段使用
production
webpack.config.js 是 webpack 的培指文件
- webpack 在真正开始打包构建之前,会先读取这个配置文件,从而基于给定的配置,对项目进行打包
注意:由于 webpack 是基于 node.js 开发出来的打包工具,因此它的配置文件中,支持使用 node.js 相关的语法和模块进行 webpack 的个性化配置
webpack 打包默认行为
默认的打包入口文件为 src -> index.js
- 默认的输出文件路径为 dist -> main.js
注意:可以在 webpack.config.js 配置文件中修改默认行为
自定义打包入口和出口
在 webpack.config.js 配置文件中,通过 entry 节点指定打包的入口。通过 output 节点指定打包的出口。
- 示例代码如下: ```javascript const path = require(‘path’) // 导入 node.js 中专门操作路径的模块
module.exprots = { entry: path.join(dirname, ‘./src/index.js’), // 打包入口文件的路径 output: { path: path.join(dirname, ‘./dist’), // 输出文件的存放路径 filename: ‘bundle.js’ // 输出文件的名字 } }
<a name="NghLh"></a>
## webpack 插件
- 安装和配置第三方插件,可以拓展 webpack 的能力,从而让 webpack 用起来更方便
- 常用的 webpack 插件有两个:
- webpack-dev-server
- 类似于 node.js 阶段用到的 nodemon 工具
- 当源代码被修改后,webpack 会自动进行项目的打包和构建
- 安装:npm i webpack-dev-server@3.11.0 -D
- 配置 webpack-dev-server
- 修改 package.json -> scripts 中的 dev 命令
```javascript
"script": {
"dev": "webpack server", // script 节点下的脚本,可以通过 npm run 执行
}
- html-webpack-plugin
- webpack 中的 HTML 插件(类似于一个模板引擎的插件)
- 可以通过此插件自定制 index.html 页面的内容
- 安装:npm i html-webpack-plugin@4.5.0 -D
- 配置 html-webpack-plugin ```javascript // 1. 导入 HTML 插件,得到一个构造函数 const HtmlPlugin = require(‘html-webpack-plugin’)
// 2. 创建 HTML 插件的实例对象 const htmlPlugin = new HtmlPlugin({ template: ‘./src/index.html’, // 指定原文件的存放路径 filename: ‘./index.html’ // 指定生成的文件的存放路径 })
module.exports = { plugins: [htmlPlugin], // 3. 通过 plugins 节点,使 htmlPlugin 插件生效 }
<a name="NGSkp"></a>
## devServer 节点
- 在 webpack.config.js 配置文件中,可以通过 devServer 节点对 webpack-dev-server 插件进行更多的配置
- 示例代码如下:
```javascript
devServer: {
open: true, // 初次打包完成后,自动打开浏览器
host: '127.0.0.1', // 是是打包所用的主机地址
port: 8080 // 是是打包所使用的端口号
}
Proxy解决本地跨域
// webpack.config.js
module.exports = {
devServer: {
proxy: {
"/api": {
target: "http://localhost:8888",
pathRewrite: { // 重写
"^/api": ""
}
}
}
}
}
resolve
extensions配置文件后缀解析
- 作用:打包时会自动匹配不带后缀的文件,并进入对应的路径目录进行查找,如有匹配则会自动添加该后缀
module.exports = {
resolve: {
extensions: [".wasm", ".mjs", ".js", ".json"], // 默认值
extensions: [".js", ".json", ".mjs", ".vue", ".ts", ".jsx", ".tsx"]
}
}
alias配置路径别名
module.exports = {
resolve: {
alias: {
"@": path.resolve(__dirname, "./src")
}
}
}
webpack插件
ClearWebpackPlugin
- 作用:打包时自动删除原有的指定打包文件,重新生成新的打包文件
```javascript // webpack.config.jsnpm install clear-webpack-plugin -D
// 导入 const { ClearWebpackPlugin } = require(‘clear-webpack-plugin’);
// 使用 module.exports = { plugins: [ new ClearWebpackPlugin() ] }
<a name="epWiv"></a>
## HtmlWebpackPlugin
- 作用:打包`index.html`文件
```bash
npm install html-webpack-plugin -D
// webpack.config.js
// 导入
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 使用(默认打包文件为原有的index.html文件)
module.exports = {
plugins: [
new HtmlWebpackPlugin()
]
}
// 扩展使用(自定义打包的index.html文件路径)
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: 'index.html文件路径'
})
]
}
DefinePlugin
该插件是
webpack
内置的
前言:
在使用HtmlWebpackPlugin
插件时可能会遇到报错问题,可能是因为BASE_URL
常量没有被定义
作用
解决HtmlWebpackPlugin
报错问题:BASE_URL
常量未定义
// webpack.config.js
// 导入
const { DefinePlugin } = require('webpack')
// 使用
module.exports = {
plugins: [
new DefinePlugin({
BASE_URL: "'./'" // 打包后BASE_URL将变成./
})
]
}
CopyWebpackPlugin
作用
将public
文件夹下的内容复制到指定的打包文件中
// webpack.config.js
// 导入
const CopyWebpackPlugin = require('copy-webpack-plugin')
// 使用
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [ // 所需要复制文件的对象,可以有多个
{
from: "public", // 复制的地址
to: "./", // 复制到的地址(一般不写)
globOptions: {
ignore: [ // 打包复制所忽略的文件
"**/index.html"
]
}
}
]
})
]
}
箭头函数转换:@babel/plugin-transform-arrow-functions
npm install @babel/plugin-transform-arrow-functions -D
$ npx babel demo.js --out-file test.js --plugins=@babel/plugin-transform-arrow-functions
# demo.js:需要转换的文件
# test.js:转换后的文件
块级作用域:@babel/plugin-transform-block-scoping
npm install @babel/plugin-transform-block-scoping -D
$ npx babel demo.js --out-file test.js --plugins=@babel/plugin-transform-block-scoping
# demo.js:需要转换的文件
# test.js:转换后的文件
loader和plugin的区别
loader
:加载模块时,通过text
去匹配该模块,并且使用和处理该模块plugins
:可以在webpack
中做任何事情,贯穿整个webpack
的生命周期
loader
- 在实际开发过程中,webpack 默认只能打包处理以 .js 后缀名结尾的模块
非 .js 后缀结尾的模块,webpack 默认处理不了,需要调用 loader 加载器才可以正常打包,否则会报错
作用
协助 webpack 打包处理特定的文件模块
css-loader
:可以打包处理 .css 相关的文件less-loader
:可以打包处理 .less 相关的文件babel-loader
:可以打包处理 webpack 无法处理的高级 JS 语法
打包处理 css 文件
安装:
npm i style-loader@2.0.0 css-loader@5.0.1 -D
在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:
module: { // 所有第三方文件模块的匹配规则
rules: [ // 文件后缀名的匹配规则
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
}
test 表示匹配的文件类型,use 表示对应要调用的 loader
注意:
安装:npm i less-loader@7.1.0 less@3.12.2 -D
在 webpack.config.js 的 module -> rules 数组中,添加loader 规则如下:
module: { // 所有第三方文件模块的匹配规则
rules: [ // 文件后缀名的匹配规则
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
]
}
打包处理样式表中与 url 路径相关的文件
安装:npm i url-loader@4.1.1 file-loader@6.2.0 -D
在 webpack.config.js 的 module -> rules 数组中,添加 loader 规则如下:
module: { // 所有第三方文件模块的匹配规则
rules: [ // 文件后缀名的匹配规则
{ test: /\.jpg|png|gif$/, use: ['url-loader?limit=22229'] }
]
}
loader 的参数项:
webpack 只能打包处理一部分高级的 JavaScript 语法
- webpack 无法处理的高级 JavaScript 语法需要借助于 babel-loader 进行打包处理
- webpack 无法处理下面的 JavaScript 代码: ```javascript class Person { // 通过 static 关键字,为 Person 类定义了一个静态属性 info // webpack 无法打包处理“静态属性”这个高级语法 static info = ‘person info’ }
console.log(Person.info)
- 配置 babel-loader
```javascript
{
test: /\.js$/,
// exclude 为排除项
// 表示 babel-loader 只需处理开发者编写的 js 文件,不需要处理 node_modules 下的 js 文件
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
// 声明一个 babel 插件,此插件用来转化 class 中的高级语法
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
}
打包处理(编译).vue文件
npm install vue-loader@next @vue/compoler-sfc -D
// webpack.config.js
const { VueLoaderPlugin } = require('vue-loader/dist/index')
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
loader: "vue-loader"
},
]
},
plugins: [
new VueLoaderPlugin()
]
}
Babel
babel
为一个独立的工具,不和webpack
等构建工具配置来单独使用- 在命令行尝试使用
babel
,需要安装如下库:@babel/core
:babel的核心代码,必须安装@babel/cli
:可以在命令行使用babel
安装
npm install @babel/core @babel/cli -D
使用
# 局部安装使用
$ npx babel demo.js --out-dir dist
# demo.js 为需要打包的文件或目录
# dist 为需要打包到的目录
# --out-dir 为打包到的地址为文件夹形式
# --out-file 为打包到的地址为文件形式
Babel预设
npm install @babel/preset-env -D
$ npx babel demo.js --out-file test.js --presets=@babel/preset-env
打包发布
- 在 package.json 文件的 scripts 节点下,新增 build 命令如下: ```javascript “scripts”: { “dev”: “webpack serve”, “build”: “webpack —mode production” }
// —mode 是一个参数项,用来指定 webpack 的运行模式 // production 表示生产环境,会对打包生成的文件进行代码压缩和性能优化
> 注意:通过 --model 指定的参数项,会覆盖 webpack.config.js 中的 model 选项
<a name="QpjD4"></a>
# Source Map
<a name="tpNOY"></a>
## 什么是 Source Map
- Source Map 就是一个信息文件,里面存储着位置信息
- Source Map 文件中存储着代码压缩混淆前后的对应关系
- 方便后期调试
<a name="b5H3z"></a>
## 开发环境下的 Source Map
- 开发环境下,webpack 默认启用了 Source Map 功能
- 程序运行出错时,可以直接在控制台提示错误行的位置,并定位到具体的源代码
- 开发环境下,推荐在 webpack.config.js 中添加如下的配置,即可保证运行时报错的行数与源代码的行数保持一致
```javascript
module.exports = {
mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
devtool: 'eval-source-map', // source-map 调错,仅在开发环境下使用
}
生产环境下的 Source Map
- 生产环境下,如果省略了 devtool 选项,则最终生成的文件中不包含 Source Map
只想定位报错的具体行数,且不想暴露源码,可以将 devtool 的值设置为 nosources-source-map
module.exports = {
mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
devtool: 'nosources-source-map'
}
想定位报错的同时展示具体报错的源码,可以将 devtool 的值设置为 source-map
module.exports = {
mode: 'development', // mode 用来指定构建模式,可选值有 development 和 production
devtool: 'source-map'
}