前言:最近公司正在做前端微服务拆分,各个服务分开打包;为了跟上脚步,动手用webpack搭建了一套vue项目;里面涉及了许多插件介绍不清楚的请自行百度,这样会加深印象
本文针对有前端基础,对webpack了解,vue项目开发
为了加深自己的理解和记忆整理下来分享给大家,跟着走一遍大概能理解webpack是在做什么事情
希望对大家有所帮助
思考
vue/react脚手架做了哪些事情
webpack在脚手架里面充当了什么角色
你对webpack的理解是什么
1、环境搭建
软件安装
node.js安装+Visual Studio Code安装
node和npm版本
package.json中依赖的插件版本
2、初始化项目
npm init
帮助我们快速初始化 package.json 文件
,中文文档
mkdir project-vue
cd project-vue
npm init // 这里可以直接写 npm init -y,不需要手动回车,接受默认值
查看 package.json
Tips:npm安装插件简写命令
“dependencies” 生产环境中中需要的
“devDependencies” 开发和测试中需要的
webpack+webpack-cli
webpack 是一个现代 JavaScript 应用程序的静态模块打包器
,中文文档
npm i webpack webpack-cli -D
安装的版本号,与官网一致webpack5.72.0
打包几要素:
- 1、入口起点
- 2、出口配置
- 3、配置模式
新增build/webpack.config.js
const path = require('path') // 引入node内置模块path
module.exports ={
mode: "development", // 开发模式
entry:'./src/main.js', // 入口文件,把src下的main.js编译到出口文件
output:{ // 出口文件
path:path.resolve(__dirname,'dist'), // 出口路径和目录
filename: "[name].js", // 编译后的名称
},
}
新增src/main.js
console.log('project-vue');
新增命令行(package.json)
{
"scripts": {
、、、
"build": "webpack --config=build/webpack.config.js"
},
}
执行命令npm run build
build文件夹生成了dist/main.js
需要把所有打包出的文件自动添加到我们可以访问的index.html,继续看下面
3、生成index.html
html-webpack-plugin
生成一个 HTML 文件,把打包生成的依赖加载进来
npm i html-webpack-plugin -D
新增index.html文件(项目根据该文件作为模版打包)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>webpack搭建vue项目</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
修改配置build/webpack.config.js
、、、
const HtmlWebpackPlugin = require('html-webpack-plugin') // 构建html文件
module.exports ={
、、、
plugins:[
new HtmlWebpackPlugin({ // 自动插入到dist目录中
title: 'webpack搭建vue项目',
}),
],
}
执行命令,生成了main.js和index.html
把根目录下的index.html作为模版文件传入到html-webpack-plugin
插件里面
、、、
module.exports ={
、、、
plugins:[
new HtmlWebpackPlugin({ // 自动插入到dist目录中
、、、
template:'./index.html',
}),
],
}
执行命令
npm run build
对比dist/index.html
和根目录index.html
,发现多了一行代码,其他的全部copy过来了。
好处是可以自己预先定义好自己所需的资源
4、核心Vue
vue项目当然需要解析vue文件,并且还能支持vue的<template>
模块写法,顺便支持jsx的写法(可不添加)
vue+vue-loader+vue-template-compiler
解析.vue文件
npm i vue@2 vue-loader vue-template-compiler -D
新增src/App.vue
<template>
<div id="app">
<h1>
hello,world!
</h1>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
修改src/main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el:'#app',
render: h => h(App)
})
修改配置build/webpack.config.js
、、、
const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue-loader编译vue文件
module.exports ={
、、、
resolve:{ // 此配置用在引用文件时
extensions: ['.js', '.vue', '.json'], // 引入路径是不用写对应的后缀名
alias:{
'vue$':'vue/dist/vue.esm.js', // 正在使用的是vue的运行时版本,而此版本中的编译器是不可用的,我们需要把它切换成运行时 + 编译的版本
'@': path.resolve(__dirname,'../src'), // 用@直接指引到src目录下
}
},
plugins:[
、、、
new VueLoaderPlugin(),
],
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
]
}
}
前方有大坑:请注意。。。。 这个坑查了很多的资料,配置了好久才搞好,反正说的都不清不楚的。
执行命令,报错找不到vue-loader/lib/plugin的模块
;百度了一下,也搜了其他的配置发现不行,高版本vue-loader+@vue/compiler-sfc试了不行。不知道是不是兼容的vue3项目,大家有遇到过么?
找到node_modules下的该插件发现确实没有这个模块
解决办法:版本降级@15
npm un vue-loader
npm i vue-loader@15 -D
npm run build
打开dist/index.html文件,展示hello,world
vue-router
vue路由配置,vue3.x对应vue-router4.x,vue2.x需要指定版本
,官方文档
npm i vue-router@3 -D
src下新增common/loginPage.vue、common/mainPage.vue
loginPage.vue :
<template>
<div>
<div>
<h1>用户登录</h1>
<p>
<label>用户名:</label>
<input>
</p>
<p>
<label>密码:</label>
<input>
</p>
<button @click="login">登录</button>
</div>
</div>
</template>
<script>
export default {
name: "loginPage",
methods: {
login() {
this.$router.push({
name: "Main"
})
},
}
}
</script>
mainPage.vue :
<template>
<div>
<div>
<button>excel导入导出功能</button>
</div>
</div>
</template>
<script>
export default {
name: "mainPage",
}
</script>
在src下新增router/index.js
import Vue from "vue";
import Router from "vue-router";
Vue.use(Router);
let routes = [];
// 登录
const loginRoute = {
path: "/login",
name: "Login",
component: () => import('../common/loginPage')
};
// 首页
const mainRoute = {
path: "/main",
name: "Main",
component: () => import('../common/mainPage') ,
};
routes.push(loginRoute, mainRoute);
routes.unshift({
path: "*",
redirect: routes[0].path,
});
const router = new Router({
routes,
});
export default router;
修改src/main.js
、、、
import router from "./router"
new Vue({
、、、
router,
、、、
})
修改src/App.vue
<template>
<div id="app">
<!-- 注入router -->
<router-view />
</div>
</template>
、、、
执行命令
npm run build
页面效果
查看项目目录
像vuex、还有一些三方UI库的引入都和在脚手架配置的差不多,这里就不一一介绍了。可以等搭建完成以后再添加这些功能
5、支持Css
你可以试试写一下样式,打包就报错,不能写css可不行;这里我用的是less预处理器,与sass相比就是轻一点
vue-style-loader+css-loader+less-loader+postcss-loader+autoprefixer
解析样式
npm i vue-style-loader css-loader less-loader postcss-loader autoprefixer -D
Tips:
vue-style-loader是基于 style-loader fork 过来的,跟 style-loader 类似
vue-style-loader除了插入 style 外,还做了一些服务端渲染的支持
vue-style-loade和style-loader只需要安装一种,都支持样式热更新
PostCSS是一款使用插件转换CSS的工具,可以用autoprefixer自动补全浏览器前缀
新增样式,修改loginPage.vue
<template>
<div class="login">
<div class="login-form">
、、、
</div>
</div>
</template>
、、、
<style lang="less" scoped>
.login {
height: 100%;
width: 100%;
overflow: hidden;
display: flex;
.bg-img {
height: 100%;
width: 100%;
}
.login-form {
position: absolute;
top: 25%;
left: 35%;
width: 400px;
height: 250px;
border: 1px solid #ffffff;
opacity: 1;
background: #ffffff;
border-radius: 10px;
}
}
</style>
修改配置build/webpack.config.js
、、、
module.exports ={
、、、
module: {
rules: [
、、、
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader',
],
},
{
test: /.less$/,
use: [
'vue-style-loader',
'css-loader',
'postcss-loader',
'less-loader'
]
},
]
}
}
新增postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
修改package.json
{
、、、
"browserslist": [
"> 1%",
"last 2 versions",
]
}
执行命令
npm run build
页面效果
查看浏览器控制台
6、支持文件、字体、图片等
asset模块
webpack5 内置了asset模块, 可以代替 file-loader、url-loader、raw-loader 等插件处理静态资源,咋们先不要管怎么配置的,能用就行,以后我们再深入了解
修改配置build/webpack.config.js
、、、
module.exports ={
、、、
module: {
rules: [
、、、
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024,
},
},
generator: {
filename: 'images/[base]',
},
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
type: 'asset',
generator: {
filename: 'files/[base]',
},
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset',
generator: {
filename: 'media/[base]',
},
},
]
}
}
新增src/assets文件夹,放一张背景图bg.png
添加图片,修改loginPage.vue
<template>
<div class="login">
<img :src="bgUrl" class="bg-img"/>
、、、
</div>
</template>
<script>
import bg from "../assets/imgs/bg.jpeg";
export default {
name: "loginPage",
data() {
return {
bgUrl: bg,
}
},
}
</script>
执行命令
npm run dev
7、热更新
现在文件里只有一个命令就是打包的,如果有了项目需要开发、调试,不希望写完页面就更新?
webpack-dev-server
webpack-dev-server 主要提供两个功能:
为静态文件提供服务
自动刷新和热替换(HMR)
npm i webpack-dev-server -D
修改配置build/webpack.config.js
、、、
module.exports ={
、、、
devServer: {
open: true, // 自动打开浏览器
hot: true, // 热更新
port: '8888' // 指定端口8888
},
}
新增命令行package.json
"dev": "webpack serve --config build/webpack.config.js",
执行命令
npm run dev
8、环境变量
如何区分当前打包的是开发环境还是正式环境,或者需要根据环境来获取不同的变量;和vue脚手架下配置.env一样
cross-env
运行跨平台设置和使用环境变量的脚本
npm i cross-env -D
修改命令行package.json
"dev": "cross-env NODE_ENV=dev webpack serve --config build/webpack.config.js",
"build": "cross-env NODE_ENV=prod webpack --config=build/webpack.config.js"
修改配置build/webpack.config.js
、、、
console.log(process.env.NODE_ENV);
module.exports ={
mode: process.env.NODE_ENV === 'prod' ? "production" : "development", // 开发模式
、、、
}
开发环境mode用development,因为追求的是打包速度,而不是体积
正式环境mode用production,因为追求的是体积小,而不是打包速度
执行命令
npm run dev / npm run build
对比一下控制台输出的文件大小和打包速度
dotenv-webpack
支持程序获取.env配置的环境变量
npm i dotenv-webpack -D
修改配置build/webpack.config.js
、、、
const Dotenv = require('dotenv-webpack'); // 支持程序获取.env配置的环境变量
module.exports ={
、、、
optimization: {
nodeEnv: false
},
plugins: [
new Dotenv({
path: path.resolve(__dirname, `../.env.${process.env.NODE_ENV}`)
})
]
、、、
}
新增.env.dev和.env.prod
.env.dev
NODE_ENV = dev
API_URL = https://mayGongDev.com
.env.prod
NODE_ENV = prod
API_URL = https://mayGongProd.com
修改App.vue
、、、
<script>
export default {
、、、
created() {
console.log(process.env.NODE_ENV);
console.log(process.env.API_URL);
}
}
</script>
、、、
执行命令
npm run dev / npm run build
查看浏览器控制台
9、Babel
Babel 是一个工具链,主要用于将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中
babel-loader+@babel/core+@babel/preset-env+@babel/runtime-corejs3+@babel/plugin-transform-runtime+core-js+@vue/babel-preset-jsx
解析es6语法和api
,官方文档
npm i babel-loader '@babel/core' '@babel/preset-env' '@babel/plugin-transform-runtime' @vue/babel-preset-jsx -D
npm i @babel/runtime-corejs3 core-js -S
Tips:
babel-loader 是将ES6等高级语法转换为能让浏览器能够解析的低级语法
@babel/core 是babel的核心模块,编译器,提供转换的API
@babel/preset-env 可以根据配置的目标浏览器或者运行环境来自动将ES2015+的代码转换为es5
@babel/plugin-transform-runtime 它会帮我自动动态require @babel/runtime 中的内容
@babel/runtime-corejs3 就是提供统一的模块化的helper, 使用能大大减少打包编译后的体积
core-js JavaScript标准库的polyfill,@babel/preset-env 引用的包
@vue/babel-preset-jsx 支持解析vue中的jsx语法
修改loginPage.vue
、、、
<script>
export default {
methods: {
login() {
this.getUser().then(res => {
if (res === '1') {
this.$router.push({
name: "Main"
})
}
});
},
getUser() {
return new Promise((resole) => {
[1,2,3].map((res) => {
console.log(res);
})
if (true) {
resole('1');
}
})
}
}
}
</script>
、、、
修改mainPage.vue
<script>
export default {
name: "mainPage",
render() {
return <div>
<div>
<button>excel导入导出功能</button>
</div>
</div>;
}
}
</script>
执行命令
npm run dev
查看浏览器控制台,发现箭头函数、Promise等没有解析,如果运行在不兼容的浏览器或其他地方就会报错
修改配置build/webpack.config.js
、、、
module.exports ={
、、、
module: {
rules: [
、、、
{
test: /\.(ts|js)x?$/,
use: [
'babel-loader',
],
exclude: /node_modules/,
},
]
}
}
新增babel.config.js文件
module.exports = {
presets: [
[
"@babel/preset-env",
{
"useBuiltIns": "usage", // 按需引入
"corejs": 3 // corejs版本
}
],
"@vue/babel-preset-jsx" // 支持vue中的jsx语法
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3 // corejs版本
}
]
]
}
执行命令
npm run dev
查看浏览器控制台
10、优化项
可配置项
clean-webpack-plugin
清理文件
npm i clean-webpack-plugin -D
修改build/webpack.config.js
、、、
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清理构建目录下的文件
module.exports ={
、、、
plugins:[
、、、
new CleanWebpackPlugin(),
],
、、、
}
或者不用插件,直接配置
、、、
const { CleanWebpackPlugin } = require('clean-webpack-plugin'); // 清理构建目录下的文件
module.exports ={
、、、
output: { // 出口文件
、、、
clean: true
},
、、、
}
progress-bar-webpack-plugin
控制台打包时显示进度条
npm i progress-bar-webpack-plugin -D
修改配置build/webpack.config.js
、、、
const ProgressBarWebpackPlugin = require('progress-bar-webpack-plugin') // 设置打包进度条
module.exports ={
stats: "errors-only", // 日志打印只打印错误和警告
、、、
plugins:[
、、、
new ProgressBarWebpackPlugin({
complete: "█",
clear: true
}),
],
}
打包效果
friendly-errors-webpack-plugin
控制台打包时优化提示
npm i friendly-errors-webpack-plugin -D
修改配置build/webpack.config.js
、、、
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin') // 优化提示
module.exports ={
、、、
plugins:[
、、、
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: { // 成功的时候输出
messages: [
'You can now view project-vue in the browser.'
],
},
clearConsole: true, // 是否每次都清空控制台
}),
],
}
mini-css-extract-plugin+css-minimizer-webpack-plugin
css样式分离和css样式压缩
npm i mini-css-extract-plugin css-minimizer-webpack-plugin -D
修改配置build/webpack.config.js
、、、
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // webpack4以后 改为此插件 css样式分离
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); // webpack5 改为此插件 css样式压缩
module.exports = {
、、、
plugins:[
、、、
new MiniCssExtractPlugin({
filename: process.env.NODE_ENV === 'prod' ? 'css/[name].[contenthash].css' : 'css/[name].css',
chunkFilename: process.env.NODE_ENV === 'prod' ? 'css/[name].[contenthash].css' : 'css/[name].css',
}),
new CssMinimizerPlugin(),
],
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === 'prod' ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
],
},
{
test: /.less$/,
use: [
process.env.NODE_ENV === 'prod' ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
'postcss-loader',
'less-loader',
],
},
],
},
}
打包效果
11、git提交支持Eslint校验
husky+lint-staged
git commit 代码检查
npm i lint-staged husky -D // 安装插件
npx husky install // 创建.husky, 会在根目录下创建.husky文件夹
npx husky add .husky/pre-commit // 添加pre-commit hooks,会生成一个pre-commit执行脚本
大坑又来了:不能手动新建.husky文件以及pre-commit,手动新建会无法触发commit的hooks
把代码推到gitee或其他代码托管网站上,再执行npx husky install
修改.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'eslint校验代码'
执行命令
git commit -m '代码校验'
查看输出
eslint+prettier
规范代码,统一风格,自动修复
npm i eslint prettier -D
./node_modules/.bin/eslint --init
选择自己项目所需的,根目录下生成.eslintrc.js文件
最终生成的文件夹
打开build/webpack.config.js发现报错‘require‘ is not defined no-undef
修改.eslintrc.js
module.exports = {
env: {
、、、
node: true // node环境
},
、、、
}
打开mainPage.vue发现报错
修改.eslintrc.js
module.exports = {
、、、
parserOptions: {
ecmaFeatures:{
"jsx": true // 支持jsx语法
},
ecmaVersion: "latest",
sourceType: "module"
},
、、、
}
git校验
git commit时 检查暂存的代码是否符合代码规范,报错并输出在控制台
修改package.json
{
"scripts": {
、、、
"lint": "npx lint-staged"
}
、、、
"lint-staged": {
"src/**/*.{js,vue}": [
"npx eslint --fix",
"git add"
]
}
}
修改.husky/pre-commit
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'eslint校验代码'
npm run lint
修改.eslintrc.js
module.exports = {
、、、
rules: {
"no-console": "error" // 关闭console
}
}
vscode安装ESLint扩展插件
执行命令git commit -m 'xxx'
,暂存区没有文件,因此也不校验
不规范代码已经标红,修改loginPage.vue
执行命令
12、项目地址
随着项目文件越来越多,越来越大,需要规范和配置的也会越来越多。
吐槽和建议,欢迎下方留言