webpack 从零构建 Vue3

webpack 从零构建 Vue3

  • [1. 构建项目](#1. 构建项目)
  • [2. webpack 相关依赖和配置](#2. webpack 相关依赖和配置)
  • [3. vue 相关](#3. vue 相关)
  • [4. 清除旧的 output 文件](#4. 清除旧的 output 文件)
  • [5. 热更新](#5. 热更新)
  • [6. 样式相关](#6. 样式相关)
    • [6.1 引入 css](#6.1 引入 css)
    • [6.2 引入 less](#6.2 引入 less)
  • [7. ts 相关](#7. ts 相关)
  • [8. webpack 输出信息优化](#8. webpack 输出信息优化)
    • [8.1 错误信息优化](#8.1 错误信息优化)
    • [8.2 专注地址](#8.2 专注地址)
  • [9. 完整关键代码](#9. 完整关键代码)

虽然我们已经可以通过 Vite 去快速的构建一个 Vue3 项目,但是使用 webpack 去构建一个Vue3 项目还是有必要的。一来让我们复习下 webpack 的项目构建流程,二来万一以后遇上老项目也能够快速上手。

1. 构建项目

创建项目文件夹,比如 webpack-vue-app

(1)初始化 package.json 包:

javascript 复制代码
npm init -y

(2)全局下载安装 typescript(如果之前没安装的话):

javascript 复制代码
npm i -g typescript

(3)生成 tsconfig.js 文件:

javascript 复制代码
tsc --init

(4)创建项目文件基本目录:public/index.html、src/assets 文件夹、src/views 文件夹、src/App.vue、src/main.ts。

其中,public/index.html:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack vue app</title>
</head>
<body>
  
</body>
</html>

2. webpack 相关依赖和配置

(5)全局下载 pnpm(如果之前没安装的话):

javascript 复制代码
npm i -g pnpm

(6)下载 webpack 相关依赖:

javascript 复制代码
pnpm add webpack
pnpm add webpack-cli
pnpm add webpack-dev-server
pnpm add html-webpack-plugin

(7)创建 webpack.config.js:

javascript 复制代码
const { Configuration } = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

/**
 * @type {Configuration}
 */
const config = {
  mode: 'development',
  entry: './src/main.ts',
  output: {
    filename: '[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    })
  ]
}

module.exports = config;

(8)package.json 添加运行和打包命令:

json 复制代码
{
  "name": "webpack-vue-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "html-webpack-plugin": "^5.6.4",
    "webpack": "^5.102.1",
    "webpack-cli": "^6.0.1",
    "webpack-dev-server": "^5.2.2"
  }
}

关键代码:

javascript 复制代码
"dev": "webpack-dev-server",
"build": "webpack"

(9)main.ts 添加一些代码,用于后续测试。比如:

html 复制代码
console.log('this is a test')

(10)执行 npm run build,生成打包后的文件

3. vue 相关

(1)安装 vue

html 复制代码
pnpm add vue
html 复制代码
pnpm add vue-loader@next
pnpm add @vue/copiler-sfc

(2)在 webpack.config.js 中使用相关的插件和 loader:

javascript 复制代码
const { Configuration } = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

const { VueLoaderPlugin } = require('vue-loader/dist/index')

/**
 * @type {Configuration}
 */
const config = {
  mode: 'development',
  entry: './src/main.ts',
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      }
    ]
  },
  output: {
    filename: '[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    }),
    new VueLoaderPlugin()
  ]
}

module.exports = config;

(3)写入 App.vue 内容,用于测试:

html 复制代码
<template>
  <div>
    123
  </div>
</template>

<script setup>

</script>

<style scoped>

</style>

(4)在 public/index.html 中,加入 id 为 app 的元素,用于后续挂载App.vue:

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack vue app</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

(5)main.ts 中引入 App.vue ,并进行挂载

typescript 复制代码
import { createApp } from 'vue'

import App from './App.vue'

createApp(App).mount('#app')

(6)打包测试,执行 npm run build

会发现,每次只要对 App.vue 或 main.ts 中的代码进行修改,就会产生新的 js 打包文件,而不会删除旧的 js 打包文件。

4. 清除旧的 output 文件

(1)方式一(老版本,不建议):下载 clean-webpack-plugin

Shell 复制代码
pnpm add clean-webpack-plugin

在 webpack.config.js 中配置:

javascript 复制代码
const { Configuration } = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

const { VueLoaderPlugin } = require('vue-loader/dist/index')

/**
 * @type {Configuration}
 */
const config = {
  mode: 'development',
  entry: './src/main.ts',
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      }
    ]
  },
  output: {
    filename: '[hash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    }),
    new VueLoaderPlugin(),
    new CleanWebpackPlugin()
  ]
}

module.exports = config;

(2)方式二(推荐):在 output 中配置 clean 即可。

webpack.config.js:

typescript 复制代码
const { Configuration } = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

const { VueLoaderPlugin } = require('vue-loader/dist/index')

/**
 * @type {Configuration}
 */
const config = {
  mode: 'development',
  entry: './src/main.ts',
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      }
    ]
  },
  output: {
    filename: '[hash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    }),
    new VueLoaderPlugin(),
  ]
}

module.exports = config;

使用 live-server 或其他方式在浏览器打开 dist/index.html 文件

5. 热更新

(1)运行 npm run dev,点击链接,打开 html 预览

(2)修改 App.vue:

javascript 复制代码
<template>
  <div>
    <h1>Hello Webpack And Vue 123</h1>
  </div>
</template>

<script setup>

</script>

<style scoped>

</style>

热更新没问题。

6. 样式相关

6.1 引入 css

(1)别名配置和后缀名配置

javascript 复制代码
resolve: {
    // 别名配置
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
    // 自动补全后缀名
    extensions: ['.vue', '.ts', '.js']
  }

(2)引入样式相关 loader

javascript 复制代码
pnpm add css-loader
pnpm add style-loader

在 webpack.config.js 的 module 中进行配置:

javascript 复制代码
module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  },

不同于vite,webpack 配置修改后,记得 npm run dev 重启。

(3)创建 assets/index.css 文件:

css 复制代码
html, body{
  margin: 0;
  padding: 0;
  height: 100%;
  background-color: aqua;
}

(4)在 App.vue 中引入使用:

javascript 复制代码
<template>
  <div>
    <h1>Hello Webpack And Vue 123</h1>
  </div>
</template>

<script setup>
import '@/assets/index.css'

</script>

<style scoped>

</style>

6.2 引入 less

(1)下载 less 和 less-loader:

javascript 复制代码
pnpm add less
pnpm add less-loader

(2)配置 webpack.config.js 中的 module:

javascript 复制代码
module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      }
    ]
  },

重新 npm run dev

(3)修改 assets/index.css 的后缀名为 less

(4)修改 App.vue 中的引用:

javascript 复制代码
<template>
  <div>
    <h1>Hello Webpack And Vue 123</h1>
  </div>
</template>

<script setup>
import '@/assets/index.less'

</script>

<style scoped>

</style>

7. ts 相关

(1)下载 typescript 和 ts-loader:

javascript 复制代码
pnpm add typescript
pnpm add ts-loader

(2)webpack.config.js 中添加配置:

javascript 复制代码
module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /\.ts$/,  //解析ts
        loader: "ts-loader",
        options: {
          configFile: path.resolve(process.cwd(), 'tsconfig.json'),
          appendTsSuffixTo: [/\.vue$/]
        },
      }
    ]
  },

(3)在 vue 文件中,就可以使用 ts了。比如,App.vue:

javascript 复制代码
<template>
  <div>
    {{ name }}123123
  </div>
</template>

<script setup lang="ts">
import '@/assets/index.less'
import { ref } from 'vue'
const name = ref<string>('Sheldon')
</script>

<style lang="scss" scoped>

</style>

8. webpack 输出信息优化

每次 npm run dev 都会输出这一堆信息,但是实际上我们只关注代码最终的server地址和报错信息。可以做下优化。

8.1 错误信息优化

webpack.config.js 的 config 中添加

javascript 复制代码
stats: 'errors-only', // 只在发生错误或警告时输出日志

重新运行npm run dev, 会发现中间的处理信息直接删除,只会有server和报错信息了。

8.2 专注地址

(1)下载 friendly-errors-webpack-plugin

javascript 复制代码
pnpm add friendly-errors-webpack-plugin

(2)在webpack.config.js 中进行配置:

javascript 复制代码
const FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin")
javascript 复制代码
plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    }),
    new VueLoaderPlugin(),
    new FriendlyErrorsWebpackPlugin({
      compilationSuccessInfo: { //美化样式
        messages: ['You application is running here http://localhost:8080']
      }
    })
  ]

重新运行 npm run dev,会发现,输出信息做了进一步优化。虽然实际上是添加了一行输出,但是实际效果会直接跳转到这一行,让我们更加专注于server地址。

9. 完整关键代码

资源下载地址:https://download.csdn.net/download/qq_39055970/92281471

(1)package.json:

json 复制代码
{
  "name": "webpack-vue-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@vue/compiler-sfc": "^3.5.24",
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^7.1.2",
    "friendly-errors-webpack-plugin": "^1.7.0",
    "html-webpack-plugin": "^5.6.4",
    "less": "^4.4.2",
    "less-loader": "^12.3.0",
    "style-loader": "^4.0.0",
    "ts-loader": "^9.5.4",
    "typescript": "^5.9.3",
    "vue": "^3.5.24",
    "vue-loader": "^17.3.1",
    "webpack": "^5.102.1",
    "webpack-cli": "^6.0.1",
    "webpack-dev-server": "^5.2.2"
  }
}

(2)webpack.config.js:

javascript 复制代码
const { Configuration } = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');

const { VueLoaderPlugin } = require('vue-loader/dist/index')
const FriendlyErrorsWebpackPlugin = require("friendly-errors-webpack-plugin")

/**
 * @type {Configuration}
 */
const config = {
  mode: 'development',
  entry: './src/main.ts',
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: 'vue-loader'
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.ts$/,  //解析ts
        loader: "ts-loader",
        options: {
          configFile: path.resolve(process.cwd(), 'tsconfig.json'),
          appendTsSuffixTo: [/\.vue$/]
        },
      }
    ]
  },
  output: {
    filename: '[hash].js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  resolve: {
    // 别名配置
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
    // 自动补全后缀名
    extensions: ['.vue', '.ts', '.js', '.json', '.tsx']
  },
  stats: 'errors-only', // 只在发生错误或警告时输出日志
  plugins: [
    new htmlWebpackPlugin({
      template: './public/index.html'
    }),
    new VueLoaderPlugin(),
    new FriendlyErrorsWebpackPlugin({
      compilationSuccessInfo: { //美化样式
        messages: ['You application is running here http://localhost:8080']
      }
    })
  ]
}

module.exports = config;

(3)tsconfig.json:

json 复制代码
{
  // Visit https://aka.ms/tsconfig to read more about this file
  "compilerOptions": {
    // File Layout
    // "rootDir": "./src",
    // "outDir": "./dist",

    // Environment Settings
    // See also https://aka.ms/tsconfig/module
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    // For nodejs:
    // "lib": ["esnext"],
    // "types": ["node"],
    // and npm install -D @types/node

    // Other Outputs
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    // Stricter Typechecking Options
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    // Style Options
    // "noImplicitReturns": true,
    // "noImplicitOverride": true,
    // "noUnusedLocals": true,
    // "noUnusedParameters": true,
    // "noFallthroughCasesInSwitch": true,
    // "noPropertyAccessFromIndexSignature": true,

    // Recommended Options
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": false,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    // "moduleResolution": "nodenext",
    "skipLibCheck": true,

    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
    },
    "allowSyntheticDefaultImports": true,
  }
}

(4)public/index.html:

javascript 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>webpack vue app</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>

(5)src/main.ts:

javascript 复制代码
import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

上一章 《Vue3 组件库 Element Plus

下一章 《Vue3 高级性能优化

相关推荐
漠月瑾-西安6 小时前
React 组件二次封装实践:解决自定义 Props 传递导致的 DOM 警告问题
typescript·ant design·react hooks·react组件封装
西芹术士10 小时前
TypeScript 5.0+ 重要新特性全面解析
typescript
拉不动的猪11 小时前
Webpack 与 Rollup 中 Tree-shaking 的实现原理与效果
前端·webpack·rollup.js
小蹦跶儿11 小时前
解决Webpack 打包报错:TypeError: Cannot assign to read only property 'exports' ?
javascript·vue.js·webpack
saadiya~19 小时前
基于 Vue3 封装大华 RTSP 回放视频组件(PlayerControl.js 实现)
前端·vue3·大华视频相机前端播放
九章云极AladdinEdu1 天前
项目分享|告别枯燥命令行,构建终端用户界面的 TypeScript 库
javascript·ui·typescript
阿珊和她的猫2 天前
Webpack Loader 和 Plugin 实现原理详解
前端·webpack·node.js
luckyzlb2 天前
03-node.js & webpack
前端·webpack·node.js
心随雨下2 天前
TypeScript中extends与implements的区别
前端·javascript·typescript