Bootstrap

从零开始搭建Webpack+Vue3标准化开发项目

20211221 从零开始搭建Webpack+Vue3标准开发项目

让我们来试写了一个适合工程化的、标准化的项目,主要是强调正确的目录结构应该是怎么样的,下文会做一些对比与分析

一、开发前准备

请确保您已经安装了node.js

二、创建项目

首先需要创建一个空目录,在该目录打开命令行,执行npm init命令创建一个项目,完成后会自动生成一个 package.json 文件。

D:\vue3-project>npm init

package name: (vue3-project)
version: (1.0.0)
description:
entry point: (index.js) main.js
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to D:\vue3-project\package.json:

{
  "name": "vue3-project",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes)

注意:我们重新指定入口文件(entry)为main.js而不是index.js。

PS:因为很多目录下都有index.js文件,经常同时打开多个index.js文件,就会导致理解混乱,看久就审美疲劳了,搞得现在看到一个女的都觉得是美女……所以,我们遵循main.js是项目的主入口文件。

添加 Webpack 配置文件

  vue3-project
  |- package.json
+ |- webpack.config.js
+ |- /public
+   |- index.html
+ |- /src
+   |- main.js

Webpack 配置如下:

webpack.config.js

'use strict'

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')

module.exports = {
    mode: 'development',
    entry: './src/main.js',
    output: {
        filename: 'index.js',
        path: path.resolve(__dirname, 'dist'),
        assetModuleFilename: 'images/[name][ext]'
    },
    resolve: {
        alias: {
            '@': path.join(__dirname, 'src')
        }
    },
    module: {
        rules: [{
                test: /\.vue$/,
                use: [{
                    loader: 'vue-loader'
                }]
            },
            {
                test: /\.css$/,
                use: [{
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader'
                    }
                ]
            },
            {
                test: /\.(png|jpe?g|gif)$/i,
                type: 'asset/resource'
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './public/index.html'
        }),
        new VueLoaderPlugin()
    ],
    devServer: {
        compress: true,
        port: 8088
    }
}

创建主页:

/public/index.html

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>这是标题</title>
    </head>
    <body>
        <div id="app"></div>
    </body>
</html>

安装依赖

npm install --save-dev css-loader html-webpack-plugin style-loader vue-loader@next @vue/compiler-sfc webpack webpack-cli webpack-dev-server
  • VueLoaderPlugin 的导入方式改变了
  • vue-loader@next 当前需要自行指定版本
  • 新增了 @vue/compiler-sfc 替换原来的 vue-template-compiler
  • 其它都是 Webpack 基本配置

三、安装Vue

npm install --save vue@next vue-router@next vuex@next

当前均需要自行指定版本

根目录添加文件

  vue3-project
  |- package.json
  |- /src
+   |- app.vue

/src/app.vue

<template>
    <ul>
        <li>
            <router-link to="/">Home</router-link>
        </li>
    </ul>
    <router-view />
</template>
  • 组件的根元素可以允许为多个
  • <router-view> 是 vue-router 定义的容器组件

/src/main.js

import { createApp } from 'vue'

import App from './app.vue'
import router from './router.js'
import store from './store'

createApp(App)
    .use(router)
    .use(store)
    .mount('#app')

不同于 Vue2.0 的整包导入方式,Vue3.0 采用了按需导入的方式,比如这里只导入了 createApp 这个方法,这样做的好处是可以支持 Webpack 的 treeshaking, 其它没有用到的部分将不会出现在最终打包文件中

createApp 方法创建了一个实例,额外的东西(router, store 等)均挂载到这个实例上,这样做的好处是不会影响到另外创建的其它实例

Vue3.0 的响应式系统使用了 ES2015 的 Proxy (代理),其浏览器兼容性参考 CanIUse,该特性无法兼容旧浏览器

四、配置Vue-Router

添加Router文件

  vue3-project
  |- package.json
  |- /src
+   |- router.js
+   |- /pages
+     |- /home
+       |- home.vue
+     |- /error
+       |- 404.vue

该文件创建并导出一个 Vue-Router实例

src/router.js

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

const routes = [{
        path: '/',
        component: require('@/pages/home/home.vue').default
    },
    {
        path: '/:catchAll(.*)',
        component: require('@/pages/error/404.vue').default
    }
]

const router = createRouter({
    history: createWebHashHistory(), //除了 createWebHashHistory,还有 createWebHistory 和 createMemoryHistory
    routes
})

export default router
  • 导入方式也为按需导入
  • 原来的 mode 参数变为 history
  • 除了 createWebHashHistory,还有 createWebHistory 和 createMemoryHistory
  • 路由未匹配时使用 '/:catchAll(.*)'

PS:有的项目中,Router文件在/src/router/index.js中,多了一层目录,当路由不复杂时,放在根目录/src/router.js更加便于查找和修改。

该文件创建并导出一个home主页的Vue组件

/pages/home/home.vue

<template>
    <h1>主页</h1>
</template>

<script>
    import { useRouter } from 'vue-router'; // 在组件中使用 router
    import { useRoute } from 'vue-router'; // 在组件中使用 route
    import { useStore } from 'vuex'; // 在组件中使用 store

    export default {
        setup() {
            const router = useRouter();
            const route = useRoute();
            const { state, getters, commit, dispatch } = useStore();

            // 也可以解构
            const { push, go, back } = useRouter();

            return {
                state
            }
        }
    }
</script>
  • router 就是原来实例的 $router,也有 beforeEach, afterEach 等等方法
  • route 是个响应式的代理对象,和原来实例的 $route 一样,也有 query, params 等属性
  • 不建议将 route 解构,解构后的 query, params 并不是响应式的

PS:有的项目中,页面文件在/src/views/下,这里改到/src/pages/下,因为在汉语翻译中,view(视图)只能表达页面中的某个部分,而page(页面)更能准确的表达这是单页面应用SPA。

该文件创建并导出一个错误页组件

/pages/error/404.vue

<template>
    <h1>404 页面不存在</h1>
</template>

五、配置Vuex Store

添加Store文件

  vue3-project
  |- package.json
  |- /src
+   |- store.js

该文件创建并导出一个 Vuex 实例

src/store.js

import { createStore } from 'vuex'

const store = createStore({
    state: {},
    getters: {},
    mutations: {},
    actions: {}
})

export default store
  • 导入方式也为按需导入
  • 其它照旧,没有什么变化

state 是响应式的代理对象,不通过 commit 提交 mutations 而是直接修改 state 也是可以的,控制台并没有给出什么警告

六、NPM Scripts 启动本地服务

在 package.json 文件对应的 scripts 处新增命令

{
    "scripts": {
        "serve": "webpack serve",
        "build": "webpack"
    }
}

执行 npm run dev 访问 localhost:8088

npm run serve

完成后,package.json文件会变成这样的

{
    "name": "vue3-project",
    "version": "1.0.0",
    "description": "",
    "main": "main.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "serve": "webpack serve",
        "build": "webpack"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "@vue/compiler-sfc": "^3.2.26",
        "css-loader": "^6.5.1",
        "html-webpack-plugin": "^5.5.0",
        "style-loader": "^3.3.1",
        "vue-loader": "^17.0.0",
        "webpack": "^5.65.0",
        "webpack-cli": "^4.9.1",
        "webpack-dev-server": "^4.6.0"
    },
    "dependencies": {
        "vue": "^3.2.26",
        "vue-router": "^4.0.12",
        "vuex": "^4.0.2"
    }
}

参考文献:

https://www.cnblogs.com/xyzhanjiang/p/13272975.html

从零开始使用 Webpack 搭建 Vue3 开发环境

;