一、简答题
1、Webpack 的构建流程主要有哪些环节?如果可以请尽可能详尽的描述 Webpack 打包的整个过程。
主要环节
-
安装webpack ,yarn add webpack@4.44.2 webpack-cli@3.3.3 -D
-
配置webpack.config.js文件
-
在webpack.config.js中配置entry, output以及mode
-
根据要加载的文件类型,安装配置不同的loader加载器
-
根据项目的需求,实现非loader的功能,安装相应的plugins
-
配置devserver 开启自动化编译和浏览器预览
-
配置optimization 进行项目优化等等操作。
2、Loader 和 Plugin 有哪些不同?请描述一下开发 Loader 和 Plugin 的思路。
Loader与Plugin的区别:
webpack只能识别javascript和json文件,而loader能够让webpack去处理更多类型的文件,让他们转换成有效的模块,形成依赖树。
Plugin插件就是处理除了loader转换模块之外的任务,比如打包优化、资源管理
Loader实现思路:
-
module.exports导出一个function接收形参source
-
处理source文件
-
返回一个js字符串
Plugins实现思路:
-
导出一个插件类,在类的原型上定义apply方法
-
webpack初始化完成,apply方法上接收compiler对象
-
通过compiler对象的钩子,定义在某个阶段注入插件,通过tabable定义钩子的触发方式
-
tabable中的方法接受插件名和一个函数,这个函数中接受compliation对象
-
通过compliation对象上的属性,执行自己想要实现的功能,比如资源类的assets
-
最后将处理后的结果给compliation上assets属性重新赋值
二、编程题
1、使用 Webpack 实现 Vue 项目打包任务 具体任务及说明:
说明:
- 安装和配置eslint
-
删除package中的eslint相关的配置.
-
yarn add eslint ,然后运行eslint --init 初始化 .eslintrc.js ,根据提示安装响应的包
yarn add eslint-plugin-vue@latest eslint-config-standard@latest eslint@^7.12.1 eslint-plugin-import@^2.22.1 eslint-plugin-node@^11.1.0 eslint-plugin-promise@^4.2.1 -D
- 安装和配置prettier
- 安装
yarn add prettier @vue/eslint-config-prettier eslint-plugin-prettier -D
- 在.eslintrc.js中添加
module.exports = {
extends: [
...
'@vue/prettier'
],
}
- 新建.prettierrc.js文件
// prettier.config.js or .prettierrc.js
module.exports = {
trailingComma: "es5",
tabWidth: 4,
semi: false,
singleQuote: true
};
- 安装和配置lint-stage和husky
- 安装
yarn add lint-staged husky -D
- 在package.json中添加
{
"scripts": {
"lint-staged:js": "eslint --ext .js,.vue,.ts",
"lint:fix": "eslint --fix --cache --ext .js,.vue,.ts --format=pretty ./src",
"lint:js": "eslint --cache --ext .js,.vue,.ts,--format=pretty ./src",
"lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
"precommit": "lint-staged",
},
"lint-staged": {
"**/*.{js,vue,ts,less,md,json}": [
"prettier --write",
"npm run lint:js",
"git add"
]
},
}
- 安装webpack
yarn add webpack@4.44.2 webpack-cli@3.3.3 -D
- 安装webpack-merge,配置多环境
yarn add webpack-merge -D
webpack.common.js中
module.exports = {
entry: "./src/main.js",
output: {},
};
webpack.dev.js中
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "development",
});
});
webpack.prod.js中
const common = require("./webpack.common");
const { merge } = require("webpack-merge");
module.exports = merge(common, {
mode: "production",
});
});
- 在webpack.common.js中配置打包入口和输出
const path = require("path");
module.exports = {
entry: "./src/main.js",
output: {
filenaem: "[name].[contenthash].js",
path: path.resolve(__dirname, "dist"),
},
};
};
- 在package.json中配置build命令
{
"scripts": {
"build": "webpack --config webpack.prod.js",
},
}
运行 yarn build命令 之后提示如下,
- 解析.vue结尾的文件
- 安装
yarn add vue-loader vue-template-compiler -D
- 在webpack.common.js中
const VueLoaderPlugin = require("vue-loader/lib/plugin");
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: ["vue-loader"],
},
],
},
plugins: [new VueLoaderPlugin()],
}
- 解析.css文件和.less文件
- 安装
yarn add css-loader style-loader -D
- webpack.common.js中
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
],
},
}
- 解析图片资源文件
- 安装
yarn add url-loader file-loader -D
- webpack.common.js中
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/i,
use: [
{
loader: "url-loader",
options: {
limit: 4096,
fallback: "file-loader",
esModule: false,
},
},
],
},
],
},
};
- 解析.js文件
- 安装
yarn add babel-loader @babel/core @babel/preset-env @vue/cli-plugin-babel eslint-loader -D
- webpack.common.js中
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
'eslint-loader',
],
},
],
},
}
- CleanWebpackPlugin、ProgressPlugin、HtmlWebpckPlugin
CleanWebpackPlugin每次构建前清除目标目录
HtmlWebpckPlugin根据index.html模板生成html文件
ProgressPlugin显示webpack构建的进度
- 安装
yarn add clean-webpack-plugin html-webpack-plugin -D
- webpack.prod.js中
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
module.exports = merge(common, {
mode: 'production',
plugins: [
new webpack.ProgressPlugin(),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: 'vue-app-base',
template: 'public/index.html',
}),
],
})
}
执行yarn build 出现BASE_URl is not defined
这个错误出现的原因是因为public下面的index.html存在一个全局变量的BASE_URL这个时候需要用DefinePlugin定义全局变量
webpack.prod.js中添加如下
module.exports = merge(common, {
plugins: [
new webpack.DefinePlugin({
BASE_URL: JSON.stringify('/'),
}),
.....
],
})
- 复制public中文件到dist目录中
- 安装
yarn add copy-plugin-webpack@5.1.2 -D
- webpack.prod.js中
const path = require('path')
const CopyPlugin = require('copy-webpack-plugin')
module.exports = {
plugins: [
new CopyPlugin([
{
from: path.join(__dirname, 'public'),
to: path.join(__dirname, 'dist'),
ignore: [
'.DS_Store',
{
glob: 'index.html',
matchBase: false,
},
],
},
]),
]
}
- 开启server并自动编译
- 安装
yarn add webpack-dev-server -D
- webpack.dev.js中
module.exports = {
devServer: {
contentBase: path.join(__dirname, 'public'),
compress: true,
open: true,
port: 9000,
},
}
- package.json中配置
{
"scripts": {
"serve": "webpack-dev-server --config webpack.dev.js --watch",
},
}
- 配置打包优化
- 安装
yarn add terser-webpack-plugin -D
- webpack.prod.js中
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin({
cache: true,
parallel: true,
sourceMap: true,
}),
],
splitChunks: {
chunks: 'all',
minChunks: 1,
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'all',
},
common: {
name: 'chunk-common',
minChunks: 2,
chunks: 'initial',
priority: -20,
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtimechunk~${entrypoint.name}`,
},
},
}
- 最后调整开发和生产的配置,如下
webpack.common.js
const path = require('path')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
'eslint-loader',
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader'],
},
{
test: /\.vue$/,
use: ['vue-loader'],
},
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 4 * 1024,
fallback: 'file-loader',
esModule: false,
},
},
],
},
],
},
plugins: [
new VueLoaderPlugin(),
new webpack.DefinePlugin({
BASE_URL: JSON.stringify('/'),
}),
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
title: 'vue-app-base',
template: 'public/index.html',
}),
],
}
webpack.dev.js
const path = require('path')
const common = require('./webpack.common')
const { merge } = require('webpack-merge')
module.exports = merge(common, {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
compress: true,
open: true,
port: 9000,
},
})
webpack.prod.js
const common = require('./webpack.common')
const { merge } = require('webpack-merge')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const path = require('path')
module.exports = merge(common, {
mode: 'production',
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin({
cache: true,
parallel: true,
sourceMap: true,
}),
],
splitChunks: {
chunks: 'all',
minChunks: 1,
cacheGroups: {
vendors: {
name: 'chunk-vendors',
test: /[\\/]node_modules[\\/]/,
priority: -10,
chunks: 'all',
},
common: {
name: 'chunk-common',
minChunks: 2,
chunks: 'initial',
priority: -20,
},
},
},
runtimeChunk: {
name: (entrypoint) => `runtimechunk~${entrypoint.name}`,
},
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin([
{
from: path.join(__dirname, 'public'),
to: path.join(__dirname, 'dist'),
ignore: [
'.DS_Store',
{
glob: 'index.html',
matchBase: false,
},
],
},
]),
],
})
先下载任务的基础代码 百度网盘链接: https://pan.baidu.com/s/1pJl4k5KgyhD2xo8FZIms8Q 提取码: zrdd
这是一个使用 Vue CLI 创建出来的 Vue 项目基础结构
有所不同的是这里我移除掉了 vue-cli-service(包含 webpack 等工具的黑盒工具)
这里的要求就是直接使用 webpack 以及你所了解的周边工具、Loader、Plugin 还原这个项目的打包任务
尽可能的使用上所有你了解到的功能和特性
作业要求
本次作业中的编程题要求大家完成相应代码后(二选一)
-
简单录制一个小视频介绍一下实现思路,并演示一下相关功能。
-
提交一个项目说明文档,要求思路流程清晰。
最终将录制的视频或说明文档和代码统一提交至作业仓库。