从零搭建基于webpack的Electron-Vue3项目(1)——基于webpack的Vue3项目搭建

2023-06-25,,

从零搭建基于webpack的Electron-Vue3项目(1)——基于webpack的Vue3项目搭建

前言

本篇文章内容,主要是基于webpack的Vue3项目开发环境进行搭建,暂时还不涉及到Electron的整合。可以独立的当作一个内容来进行阅读。

项目创建

创建目录electron-vue3-webpack并进入执行npm init命令。设置了基础的项目信息后,我们开始本次的环境搭建之旅。

使用webpack

前置条件

基本熟悉webpack是什么以及它打包的运行处理过程。

环境准备

前端编写

项目根目录创建src\renderer目录,用于存放前端代码。向其中编写一个简单的前端页面以及JS:

    src\renderer\index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>It's Title</title>
</head>
<body>
</body>
</html>
    src\renderer\main.js
console.log(document.title); // 控制台输出html的title

webpack安装

命令行执行npm install -D webpack

HtmlWebpackPlugin插件安装

接下来安装webpack插件HtmlWebpackPlugin。该插件主要生成html,这里我们配置该插件template为上述index.html,配置方式见下文webpack插件配置部分。执行命令npm install --save-dev html-webpack-plugin

配置webpack

在项目根目录下创建webpack.config.js,内容如下:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/renderer/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/renderer/index.html' // 配置html模板文件
})
]
};

至此,一个webpack的基础环境配置完成:

打包运行

    命令行执行npx webpack
    完成编译检查dist目录;
    使用浏览器打开dist/index.html,并检查控制台。

实际上,当你查看dist中的html的时候你会发现,webpack打包为我们引入了生成的js:

目前为止,我们完成了webpack的基础环境搭建以及试运行。接下来我们将引入Vue3,并以webpack打包的方式来进行Vue3的项目搭建。

使用Vue3

实际上,无论是Vue2还是Vue3,引入Vue并使用webpack来进行打包的原理都是一样的。

引入Vue3、Vue-Router以及Vuex组件

安装Vue3

# 最新稳定版
$ npm install vue@next -S

创建App.vue根组件

renderer目录下创建App.vue文件,内容如下:

<template>
<router-view/> <!-- router-view必须要引入Vue-Router组件,下文进行配置 -->
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

安装Vue-Router

$ npm install vue-router@next -S

创建Router实例

renderer目录下创建router目录,并增加index.js文件,其中内容如下:

import {createRouter, createWebHashHistory} from 'vue-router';

const routes = [ // 路由内容暂不配置
// {
// path: '/',
// name: 'Home',
// component: Home
// },
]; const router = createRouter({
history: createWebHashHistory(),
routes
}); export default router;

安装Vuex

$ npm install vuex@next -S

创建Vuex实例

renderer目录下创建store目录,并增加index.js文件,其中内容如下:

import {createStore} from 'vuex';

export default createStore({
state: {},
mutations: {},
actions: {},
modules: {}
});

编写main.js以及模板html

    src\renderer\index.html中的<body>标签中,添加<div id="app"></div>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>It's Title</title></head>
<body>
<div id="app"></div>
</body>
</html>
    修改src\renderer\main.js代码:
import { createApp } from 'vue'
import App from './App.vue' // 引入上述
import router from './router' // 引入上述编写的router实例
import store from './store' // 引入上述vuex实例 createApp(App).use(store).use(router).mount('#app') // 链式加载,"#app"指代模板中<div id="app">

至此,目前的项目结构如下:

然而,当我们进行了上述一系列的配置以后,再次运行webpack却发现,报错了:

从报错信息可以看出,当webpack想要解析App.vue文件时候,报错提示我们:You may need an appropriate loader to handle this file type(你或许需要一个对应的loader来处理这种文件类型)。

了解到webpack打包机制的读者很容易知道,我们需要安装Vue对应的loader

安装Vue-Loader

较为熟悉的同学可能立马去官方的指引文件看文档了,其实官方文档也已经相当详细的说明了Vue-Loader的配置方式,详情见链接。(注意:截至2020/11/22文档还是Vue2版本下的配置,也许你在看的时候,已经正式替换为了Vue3的正确配置了)

    安装vue-loader

    修改webpack.config.js配置。

我也天真的以为Vue3的webpack也是这样的,然而最后吃了闭门羹。实际上,Vue3大不一样,接下来将有一系列的组件进行安装,在此之前我们先记录下当前的依赖:

  "devDependencies": {
"html-webpack-plugin": "^4.5.0",
"webpack": "^5.6.0",
"webpack-cli": "^4.2.0"
},
"dependencies": {
"vue": "^3.0.2",
"vue-router": "^4.0.0-rc.5",
"vuex": "^4.0.0-rc.1"
}

接着说Vue3的改变。事实上,Vue3的loader已经有了如下的变更:

    vue-loadernpm包为截至2020/11/22,版本为:v16.0.0-rc.2,该版本安装时需要指定版本
npm install -D vue-loader@v16.0.0-rc.2
    VueLoaderPlugin 的导入方式已经发生改变:
// 原先方式:
const VueLoaderPlugin = require('vue-loader/lib/plugin')
// 全新方式:
const { VueLoaderPlugin } = require('vue-loader')
    移除vue-template-compiler,新增了@vue/compiler-sfc

vue-template-compiler在Vue2中是配合vue-loader组件,在Vue3中被移除了,取而代之的事@vue/compiler-sfc

npm install -D @vue/compiler-sfc

当然,为了让webpack处理.vue文件中的<style>块,以及各种css、图片等资源,我们添加一些常规的loader

npm install -D css-loader style-loader file-loader

至此,我们的package.json的依赖部分如下,大家自行对比:

  "devDependencies": {
"@vue/compiler-sfc": "^3.0.2",
"css-loader": "^5.0.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.0",
"style-loader": "^2.0.0",
"vue-loader": "^16.0.0-rc.2",
"webpack": "^5.6.0",
"webpack-cli": "^4.2.0"
},
"dependencies": {
"vue": "^3.0.2",
"vue-router": "^4.0.0-rc.5",
"vuex": "^4.0.0-rc.1"
}

配置webpack

在上述步骤的基础上,我们终于可以进行webpack的配置编写,直接上配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {VueLoaderPlugin} = require('vue-loader');
module.exports = {
entry: './src/renderer/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'file-loader',
options: {
esModule: false, // esModule主要为了处理require图片报错的问题
}
}
],
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/renderer/index.html'
}), // 请确保引入这个插件来施展魔法
new VueLoaderPlugin()
]
};

这个配置的每一项的功能,不再赘述。不清楚的可以复习一下webpack配置,链接在此。

webpack打包Vue3

迎来最后一步打包操作:npx webpack,输出对应成功结果,然后在dist目录下检查一下打包结果即可。

$ npx webpack

后续

当然,目前的demo没有任何实质的代码,还不能确保我们的工程有效。接下来的内容,我们继续编写Vue3的组件,完成一个简单的涵盖路由跳转的Example。

编写Example

编写一个Home页面、Plus页面的example,涵盖Vue3的一些新特性,API具体功能见官方网站。Example具体内容:

Home页面包含一个add按钮,以及可点击的卡片GO Plus Page
当点击add按钮时,页面上数字+1,同时会调用VuexAPI来完成向store.number的提交+1操作;
点击GO Plus Page卡片,调用Vue RouterAPI跳转到Plus页面;
Plus界面会显示store.number当前值,以及完成加载后会以50%概率随机加载2张(edge和chrome图标)图片的其中1张。

整体结构

Home、Plus页面

<!-- Home.vue -->
<template>
<div class="home">
<p>{{ 'number = ' + number }}</p>
<button @click="add">add</button>
<div class="card" @click="cardClick">
<p>GO Plug Page</p>
</div>
</div>
</template> <script>
// 从 vue 中引入 ref 函数
import {ref} from 'vue';
import {useRouter} from "vue-router";
import {useStore} from "vuex"; export default {
name: "Home",
setup() {
// 用 ref 函数包装一个响应式变量 number
let number = ref(0); let store = useStore(); let router = useRouter(); // 设定一个方法
function add() {
// number是被ref函数包装过了的,其值保存在.value中
number.value++;
// Vuex提交
store.commit('plus', {num: 1});
} // 定义卡片点击,进行路由跳转
function cardClick() {
router.push('/plus');
} // 将 成员 返回出去,供template中使用
return {number, add, cardClick};
}
};
</script>
<style scoped>
</style> <!-- Plus.vue -->
<template>
<div style="text-align: center">
<p>Refresh this page and you will see the icon change</p>
<div class="img-display">
<img :src="imgSrc" alt="">
</div>
<div class="number-display">
<p>{{ 'state.number = ' + state.number }}</p>
</div>
</div>
</template> <script>
import {useStore} from "vuex";
import {computed} from "vue"; export default {
name: "Plus",
setup() {
const state = useStore().state;
const imgSrc = computed(() => {
let randomBool = (Math.ceil(Math.random() * 10)) % 2 === 0;
if (randomBool) {
return require('../assets/img/edge.png');
} else {
return require('../assets/img/chrome.png');
}
}); // 计算属性
return {
state,
imgSrc
};
}
};
</script>
<style scoped>
</style>

Vuex、Router

// ---------------------------
// src/renderer/store/index.js
// ---------------------------
import {createStore} from 'vuex'; export default createStore({
state: {
number: 0,
},
mutations: {
plus(state, {num}) {
state.number += num;
}
},
actions: {},
modules: {}
}); // ----------------------------
// src/renderer/router/index.js
// ----------------------------
import {createRouter, createWebHashHistory} from 'vue-router';
// 定义路由组件, 注意,这里一定要使用 文件的全名(包含文件后缀名)
import Home from "../views/Home.vue";
import Plus from "../views/Plus.vue"; const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/plus',
name: 'Plus',
component: Plus
}
]; const router = createRouter({
history: createWebHashHistory(),
routes
}); export default router;

效果

PS:Plug页面刷新后,会清空state.number的内容所以归零。

再议webpack——热部署开发

上述进行开发的过程中,我们的流程始终的开发过程为:

    webpack配置;
    项目编码;
    npx webpack
    通过IDE查看页面结果,若需要修改,则回到步骤2。

实际开发中,我们会发现如下的一个问题:文件改动后,需要重新执行npx webpack命令完成编译,耗时麻烦。

watch参数

这个过程解决起来特别的简单,webpack实际上提供了运行参数watch,该参数简单来说就是在第一次调用以后并不会直接退出webpack,而会有一个单独的进程来监听webpack配置中指定入口代码执行以来整个依赖文件的变动,一旦发生了改变,则会立刻进行重新编译。关于watch参数详情,见此链接:Watch and WatchOptions | webpack。

使用方式简单来说:

启动 webpack 命令时,带上--watch参数
配置 webpack.config.js 中设置 watch:true

这里我们使用前者

// package.json
...
"scripts": {
"build-vue3-with-webpack": "npx webpack --watch" // 添加watch参数
},
...

运行脚本后,你会看到控制台并不会在完成编译后退出,而是hold住的,且命令行最下方显示:

webpack 5.6.0 compiled successfully in 4621 ms
[webpack-cli] watching files for updates... // 监听文件更新

每当你修改了文件,你会发现命令行会有编译更新:

其实到了这一步后,开发效率已经有了很大的提升。然而有想法的开发人员会发现,倘若每次进行更新了文件,就要重新等待webpack进行编译,随着项目文件的越来越多,时间也会越来越就久,甚至到了后期,编译一次就要几分钟。其实webpack还有一个超级有用的开发者工具:webpack-dev-server

webpack-dev-server

使用webpack-dev-server的好处是修改了后不需要刷新浏览器,同时,该模块不会将文件编译输出为最终文件,而是放在内存中,转换起来很快。

安装

$ npm install webpack-dev-server -D // 请注意 —D 开发依赖

配置以及使用

webpack.config.js

需要在webpack配置文件中增加devServer节点,告知 dev server,从什么位置查找文件(但并不意味着会生成文件到该指定位置):

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {VueLoaderPlugin} = require('vue-loader');
module.exports = {
entry: './src/renderer/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
devServer: { // 新增devServer节点
contentBase: './dist', // 告知dev server从什么位置查找
},
...
}
package.json/scripts

添加一个可以直接运行 dev server 的 script:

{
"name": "electron-vue3-webpack",
...
"scripts": {
"build-vue3-with-webpack": "npx webpack --watch",
"start": "webpack serve --open" // 新增脚本,启动webpack-dev-server
},
...
}

完成配置后,我们关闭之前的"npx webpack --watch",使用新的start脚本运行程序。然后进行开发:

这里和上面watch的区别在于:

    没有实际的dist目录以及编译后的前端文件生成;
    浏览器页面无需手动刷新页面,会自动进行;

关于webpack-dev-server的相关信息,可以进一步参考官方文档:开发环境 | webpack (docschina.org)

从零搭建基于webpack的Electron-Vue3项目(1)——基于webpack的Vue3项目搭建的相关教程结束。

《从零搭建基于webpack的Electron-Vue3项目(1)——基于webpack的Vue3项目搭建.doc》

下载本文的Word格式文档,以方便收藏与打印。