如何在 Ubuntu 20.04 上使用 Nginx 发布 Vuetify 应用程序

作者选择了 多样性在技术基金作为 写给捐款计划的一部分接受捐款。

介绍

组件是现代前端开发的一个关键特征 component 是一个代码,通常包括两个部分:

  • 组件的逻辑:组件能做什么
  • 模板:用户将如何与Web应用程序互动

将应用程序组织成组件可以帮助您编写现代而强大的 Web 应用程序。 JavaScript框架,如 ReactVue.js,可以帮助您开发许多类型的组件,并且被开发人员广泛使用。

然而,这些框架的痛点之一是,您需要创建许多组件,即使是简单的东西,如输入文本字段. 因此,一个更简化的方法是使用组件库,其中有准备好的组件,您可以根据需要选择和使用。

对于 Vue.js,有 Vuetify,一个基于 Material Design原则的 Vue UI 库。Vuetify 高度可配置和可自定义。您可以修改组件以满足您的需求,您可以设置自己的主题以根据您的品牌风格拥有一致的组件库。

在本教程中,您将创建一个基于Vuetify的任务应用程序,并使用Nginx作为反向代理程序发布它,这需要部署Vue应用程序。

<$>[注] **注:**由于Vue是一个前端框架,您为本教程创建的应用程序将在浏览器中运行。

前提条件

要遵循本教程,您将需要以下内容:

  • 一个 Ubuntu 20.04 服务器与 sudo 非 root 用户. 要开始,请遵循我们的 初始服务器设置指南 Ubuntu 20.04。 对于本教程,非 root 用户是 sammy.
  • Nginx 安装,你可以通过遵循步骤 1-3 的教程, How To Install Nginx on Ubuntu 20.04
  • 一个完全注册的域名. 本教程将使用 your_domain 整个. 你可以购买一个域名在 Namecheap,获得一个免费的在 Freenom,或使用您选择的域名注册器。 _* Node.js (至少 v14.0.0.0) 安装,你可以通过以下的 [

步骤 1 - 设置您的Vue应用程序

在此步骤中,您将配置您的 Vue.js 应用程序. Vue.js 有一个客户端,您可以使用它来创建项目的锅炉板,这是从头开始的好方法。

您将开始使用此命令在全球范围内安装 Vue.js 客户端:

1sudo npm install -g @vue/cli

接下来,验证版本:

1vue --version

当本教程编写时的最新版本是5.0.8:

1[secondary_label Output]
2@vue/cli 5.0.8

现在你已经安装了@vue/cli,你可以使用它来创建vuejs应用程序. 在本教程中,该应用程序将被称为vuetify-meets-nginx-app,但你可以更名为任何你想要的。

要创建应用程序,请运行此命令:

1vue create vuetify-meets-nginx-app

这个命令是交互式的,有多个选项. 对于本教程,选择Vue 2默认选项:

1[secondary_label Output]
2Vue CLI v5.0.8
3? Please pick a preset: (Use arrow keys)
4  Default ([Vue 3] babel, eslint)
5❯ Default ([Vue 2] babel, eslint)
6  Manually select features

<$>[警告] 警告: 在此写字时,‘Vuetify’不支持‘Vue.js v3’。

1[secondary_label Output]
2Error: you cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.**

有关更多信息,请参阅 Vuetify路线图

一旦应用程序被创建,你会注意到Vue生成的文件和目录:

 1├── README.md
 2├── babel.config.js
 3├── jsconfig.json
 4├── node_modules
 5├── package-lock.json
 6├── package.json
 7├── public/
 8      ├── favicon.ico
 9      └── index.html
10├── src
11        ...
12└── vue.config.js

这里有一个简短的概述:

  • babel.config.js: Babel是一个JavaScript编译器,并且该文件定义了它的行为。 这是运行,构建和生成最终应用程序所必需的
  • jsconfig.json: 这个文件也需要编译应用程序。 例如,这个文件将JavaScript代码的版本设置为 ECMAScript 2009 (ES5),默认的主要配置文件。 有关更多信息,请参阅 此文档
  • node_modules: 包含所有已安装和配置的库的目录。
  • package.json: 您的应用程序的主要配置文件. 您将在这里看到有关运行或

src文件夹中,你会看到以下文件和目录:

1src
2├── App.vue
3├── assets
4│ ├── logo.png
5│ └── logo.svg
6├── components
7│ └── HelloWorld.vue
8├── main.js

这里有一个简短的概述:

  • App.vue: Vue.js 应用程序的顶级组件. 所有其他组件将位于这里定义的组件内
  • assets: 所有资产,如图像、CSS 文件和字体,必须放在这里
  • components: 这包含您创建的所有组件。 @vue/cli 命令生成了一个名为 HelloWorld.vue
  • main.js: 应用程序的主要文件. 如果您需要配置库或插件,这是该文件。

现在你可以导航到‘vuetify-meets-nginx-app’目录:

1cd vuetify-meets-nginx-app

要在开发模式下启动应用程序,请运行以下命令:

1npm run serve

你的输出将看起来像这样:

 1[secondary_label Output]
 2INFO Starting development server...
 3
 4DONE Compiled successfully in 27235ms
 5
 6 App running at:
 7 - Local:   http://localhost:8080/
 8 - Network: unavailable
 9
10 Note that the development build is not optimized.
11 To create a production build, run npm run build.

开发服务器启动后,转到localhost:8080,查看应用程序:

Default home screenshot of a VueJS application

<$>[注] 注: 如果您正在远程服务器上遵循教程,您可以使用端口转发来查看浏览器中的应用程序。 确保端口 8080 在您的服务器上打开。

1ssh -L 8080:localhost:8080 your_non_root_user@your_server_ip

当您连接到服务器时,请在本地计算机的网页浏览器上导航到http://localhost:8080。在本教程的剩余时间里保持第二个终端开放。

在此步骤中,您创建了 Vue.js 应用程序,然后将 Vuetify 添加到项目中。

步骤 2 — 将Vuetify集成到Vue应用程序中

在此步骤中,您将添加Vuetify到您的Vue.js应用程序。

没有像Vuetify这样的组件库,您将不得不使用HTML输入,如div按钮,为您的Web应用程序设计CSS,并创建自己的组件,如果您想要一些可重复使用的块。

Vuetify 也是高度可自定义的。例如,你可以有主题。一个主题是 CSS 库,其中包括颜色板、自定义屏幕大小和字体等内容。例如,如果你的主要颜色是蓝色,你可以这样配置 Vuetify,每次你使用 CSS 类主要,Vuetify 都会使用蓝色。你可以在 Vuetify 文档中找到有关主题的更多信息。有关这些和其他组件的更多信息可以在 Vuetify 功能指南找到。

要开始添加 Vuetify,请通过在开发服务器运行的终端中键入CTRL+C来终止您在前一步启动的开发服务器。

接下来,在vuetify-meets-nginx-app目录中运行以下命令:

1vue add vuetify

此命令使用 Vue.js 客户端安装 Vuetify。

在预设选项列表中选择默认配置:

 1[secondary_label Output]
 2📦  Installing vue-cli-plugin-vuetify...
 3
 4added 38 packages, and audited 39 packages in 2s
 5
 67 packages are looking for funding
 7  run `npm fund` for details
 8
 9found 0 vulnerabilities
10✔  Successfully installed plugin: vue-cli-plugin-vuetify
11
12? Choose a preset: (Use arrow keys)
13  Configure (advanced)
14❯ Default (recommended)
15  Vite Preview (Vuetify 3 + Vite)
16  Prototype (rapid development)
17  Vuetify 3 Preview (Vuetify 3)

几分钟后,您可以重新启动开发服务器:

1npm run serve

导航到localhost:8080,在那里你可以看到应用程序具有新的vuetified风格:

Default home screenshot of a VueJS application with Vuetify installed

在此时刻,你已经创建了一个基本的应用程序,并添加了Vuetify来设计风格,接下来,你将创建一个具有额外功能的任务应用程序。

步骤 3 — 创建 To-Do Vuetify 应用程序

在此步骤中,您将创建一个任务应用程序. 一个任务应用程序是需要一些基本功能的任务列表:

  • 添加新任务的一种方式
  • 将其标记为完成的一种方式
  • 显示它们的一种方法,允许用户看到正在等待的内容

要将这些功能添加到您的应用程序中,您将修改App.vue文件,这是应用程序的顶级组件。

<$>[注] 注: Vue.js和许多其他框架一样,默认情况下使用 hot reloading. 如果在开发代码时继续运行npm run serve命令,您将在保存更改后在浏览器中看到更新。

导航到src/App.vue,然后使用nano或您最喜欢的文本编辑器进行编辑:

1cd src
2nano App.vue

这里是默认代码:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2<template>
 3  <v-app>
 4    <v-app-bar
 5      app
 6      color="primary"
 7      dark
 8    >
 9      <div class="d-flex align-center">
10        <v-img
11          alt="Vuetify Logo"
12          class="shrink mr-2"
13          contain
14          src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
15          transition="scale-transition"
16          width="40"
17        />
18
19        <v-img
20          alt="Vuetify Name"
21          class="shrink mt-1 hidden-sm-and-down"
22          contain
23          min-width="100"
24          src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
25          width="100"
26        />
27      </div>
28
29      <v-spacer></v-spacer>
30
31      <v-btn
32        href="https://github.com/vuetifyjs/vuetify/releases/latest"
33        target="_blank"
34        text
35      >
36        <span class="mr-2">Latest Release</span>
37        <v-icon>mdi-open-in-new</v-icon>
38      </v-btn>
39    </v-app-bar>
40
41    <v-main>
42      <HelloWorld/>
43    </v-main>
44  </v-app>
45</template>
46
47<script>
48import HelloWorld from './components/HelloWorld';
49
50export default {
51  name: 'App',
52
53  components: {
54    HelloWorld,
55  },
56
57  data: () => ({
58    //
59  }),
60};
61</script>

每个组件有两个部分:一个模板(通常是HTML代码)和一个具有JavaScript功能的脚本。

模板是最终用户将在浏览器中看到的内容,并决定用户如何与您的应用程序互动. 通常,您必须导入在模板中使用的组件,但由于您安装了‘Vuetify’作为插件,所有组件都可在模板中使用,而无需明确导入。

在模板块中,有很多v- HTML 标签,虽然这些标签对于 HTML 来说不是标准的,但这些标签是 Vuetify 组件,并且总会从v- 开始。

在 template 中,您目前有:

●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●

至于App.vue文件中的脚本块,Vuetify 安装不会在这里添加任何代码,所以你所拥有的是由Vue cli命令生成的起始代码和Vue 组件所需的最低代码。

现在你已经查看了App.vue文件中的默认代码,你已经准备好开始创建你的任务应用程序。

清除 App.vue 文件

默认的HelloWorld组件不需要你的任务应用程序,所以你会从App.vue文件中删除它。

要在另一个组件或视图中使用 Vue 组件,您必须将该组件导入到文件的脚本块中。

1[label vuetify-meets-nginx-app/src/App.vue]
2...
3import HelloWorld from './components/HelloWorld';
4...

由于您不会使用此组件,请删除导入行。

下一步是将该组件从App.vue页面的组件依赖列表中删除,在脚本块中找到以下行:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<script>
 4  ...
 5
 6  components: {
 7    HelloWorld,
 8  },
 9
10  ...
11</script>

组件列表中删除HelloWorld行。

最后一步是从模板块中删除它:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<template>
 4    ...
 5    <v-main>
 6      <HelloWorld/>
 7    </v-main>
 8  </v-app>
 9</template>
10...

删除HelloWorld行。

现在已删除默认的HelloWorld组件,您可以开始创建您的任务应用程序。

添加组件数据字段

组件的数据是一个函数,返回了您可以在模板中使用的所有数据模型,所有这些数据模型都是对象中的JavaScript变量,也可通过组件的方法访问。

脚本块中找到数据字段:

1[label vuetify-meets-nginx-app/src/App.vue]
2...
3<script>
4  ...
5  data: () => ({
6    //
7  }),
8};
9</script>

您将更改数据函数以存储您的任务列表. 将以下突出的行添加到数据函数:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<script>
 4    ...
 5    data: () => ({
 6        tasks: ['task 1', 'task 2', 'task 3'],
 7        newTask: null
 8    }),
 9};
10</script>

通过此更新,您添加了两个数据模型:存储任务名称的newTask变量和任务列表的tasks

<$>[注] 注: 如果您不熟悉Vue.js如何使模板和组件的方法可访问数据模型,请参阅官方文档中的Vue.js的反应基础(https://vuejs.org/guide/essentials/reactivity-fundamentals.html) <$>

向您的应用程序添加功能

在 Vue.js 组件中,功能位于名为方法的函数列表中。在数据模型下方的脚本块中,添加突出的行以添加三个函数:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<script>
 4export default {
 5    name: 'App',
 6
 7    data: () => ({
 8        tasks: ['task 1', 'task 2', 'task 3'],
 9        newTask: null
10    }),
11    methods: {
12        addNewTask() {
13            this.tasks.push(this.newTask);
14            this.clearNewTask();
15        },
16        clearNewTask() {
17            this.newTask = '';
18        },
19        removeTask(i) {
20            this.tasks.splice(i, 1);
21        }
22    }
23};

您添加了三个功能:

  • addNewTask: 将newTask数据模型中的新任务添加到tasks列表中
  • clearNewTask: 为newTask清除数据模型
  • removeTask: 根据数组索引从tasks中删除任务

您现在已经为您的任务应用程序添加了功能,接下来,您将更改模板以使用方法。

更新寺庙

在本节中,您将更新模板以使用您在上一节中添加的方法和数据模型。

你需要从v-app-bar中删除一些你不需要的组件,然后删除v-btn块,然后你的代码会看起来像这样:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2<template>
 3    <v-app>
 4        <v-app-bar
 5            app
 6            color="primary"
 7            dark
 8        >
 9        <div class="d-flex align-center">
10            <v-img
11                alt="Vuetify Logo"
12                class="shrink mr-2"
13                contain
14                src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
15                transition="scale-transition"
16                width="40"
17            />
18
19            <v-img
20                alt="Vuetify Name"
21                class="shrink mt-1 hidden-sm-and-down"
22                contain
23                min-width="100"
24                src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
25                width="100"
26            />
27        </div>
28
29        <v-spacer></v-spacer>
30
31        </v-app-bar>
32        ...
33    </v-app>
34</template>

接下来,您将添加一些组件来定义您的应用程序的基本布局. 首先是v-container,这是一个组件,它提供了中心和横向贴你的应用程序的内容的能力。

v 容器中,您将添加一个v-card组件,这是另一个 Vuetify 容器。 它有助于在屏幕上组织内容,如面板或静态图像。 有关v-card组件的更多信息,请参阅 Vuetify 卡文件

在当前模板中找到v-main块,并添加突出的行:

1[label vuetify-meets-nginx-app/src/App.vue]
2...
3<v-main>
4    <v-container>
5        <v-card elevation="0">
6        </v-card>
7    </v-container>
8</v-main>
9...

正如您在代码中所看到的,在v-card组件中存在一个 elevation="0``属性。Elevation 是 Vuetify 组件内部的一种常见属性,可调整两个组件之间的相对 z 距离。在这种情况下,您不需要任何距离,而0`是删除 elevation 的值。 但是,您可以玩它来查看差异或查看 升降文档

接下来,您将使用两个v-card功能组件: v-title,为卡头提供默认字体大小和插件,以及 v-card-text,其中将包含卡片的内容。

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-main>
 4    <v-container>
 5        <v-card elevation="0">
 6            <v-card-title></v-card-title>
 7            <v-card-text></v-card-text>
 8       </v-card>
 9    </v-container>
10</v-main>
11...

功能组件是一个只渲染模板的组件,它没有任何逻辑,因为它只是一个模板,所以它更快地渲染。 有关功能组件的更多信息,或者了解如何创建自己的组件,请参阅 Vue.js 功能组件指南

现在你已经有了容器组件,你必须添加一个 v-text-field 组件来处理新任务的名称。

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-main>
 4    <v-container>
 5        <v-card elevation="0">
 6            <v-card-title>
 7              <v-text-field
 8                v-model="newTask"
 9                label="Task Name"
10                prepend-icon="mdi-content-save"
11                clear-icon="mdi-close-circle"
12                clearable
13                filled
14                type="text"
15                @click:prepend="addNewTask"
16                @click:clear="clearNewTask"
17                ></v-text-field>
18            </v-card-title>
19           ...
20        </v-card>
21    </v-container>
22</v-main>
23...

「v-text-field」是命名新任务所需的组件。

它具有以下属性:

  • v-model="newTask" 将数据模型附加到组件中。你在输入中插入的任何文本也将被添加到数据模型中
  • `label="Task Name" 是输入类型的位置标记中的文本
  • `prepend-icon="mdi-content-save" 会显示文本框的左角中的 Save 标记
  • `clear-icon="mdi-close-circle" 是 Clear 按钮的标记
  • clearable' 显示了 **Clear** 标记 filled applies` to the component( _

下一步是显示任务列表模型中的每个任务。 为此,您将使用 v-timeline 组件,该组件是显示时间或顺序信息的显示组件。

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-main>
 4    <v-container>
 5        <v-card elevation="0">
 6            <v-card-title>
 7            ...
 8            </v-card-title>
 9            <v-card-text>
10              <v-timeline
11                  v-if="tasks.length > 0"
12                  dense
13              ></v-timeline>
14            </v-card-text>
15            ...
16      </v-card>
17   </v-container>
18</v-main>
19...

v-timeline 显示列表中的所有任务. v-if 仅显示数据模型中至少有一个任务的组件。

现在,要显示每个任务的名称,您需要使用一个v-timeline功能组件:v-timeline-item

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-main>
 4    <v-container>
 5        <v-card elevation="0">
 6            <v-card-title>
 7            ...
 8            </v-card-title>
 9            <v-card-text>
10              <v-timeline
11                  v-if="tasks.length > 0"
12                  dense
13                >
14                    <v-timeline-item
15                        v-for="(t, index) in tasks"
16                        :key="index"
17                    >
18                         {{ t }}
19                    </v-timeline-item>
20              </v-timeline>
21            </v-card-text>
22        </v-card>
23    </v-container>
24</v-main>
25...

此代码使用一个 v-for循环来显示任务列表模型中的每个任务的 v-timeline-item 组件. 由于 v-timeline-itemv-timeline 的功能组件,它将以时间列表的风格进行渲染。

您将索引添加为v-for循环的密钥,因为它对于v-for视图指令是强制性的。

使用{{t }}行,您将在v-timeline-item组件中显示任务的名称。

下一步是添加一个按钮来从列表中删除任务,但在此之前,您需要添加一些额外的网格系统组件来组织任务名称和按钮。

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-main>
 4    <v-container>
 5        <v-card elevation="0">
 6            <v-card-title>
 7            ...
 8            </v-card-title>
 9            <v-card-text>
10              <v-timeline
11                  v-if="tasks.length > 0"
12                  dense
13                >
14                    <v-timeline-item
15                        v-for="(t, index) in tasks"
16                        :key="index"
17                    >
18                        <v-row class="display-1 text-capitalize">
19                            <v-col cols="7">
20                                {{ t }}
21                            </v-col>
22                            <v-col
23                                class="text-right"
24                                cols="5"
25                            >
26                            </v-col>
27                        </v-row>
28                     </v-timeline-item>
29               </v-timeline>
30             </v-card-text>
31         </v-card>
32     </v-container>
33</v-main>
34...

用上面的代码,你添加了:

  • 一个v-row组件有两个类来设置任务文本的大小(display-1,类似于H1在HTML中)和所有字母大写(text-capitalize)的组件。 *一个v-col组件在行内显示每个任务的名称,需要7/12部分的空间(cols="7属性)。 *另一个v-col组件放置删除按钮。

最后,是时候添加一个 v-btn 组件,将 removeTask 函数附加到一个按钮组件上。 为了保持简单,你将使用一个 icon button,这是一个只有一个图标而没有文本的按钮。

添加突出的线条:

 1[label vuetify-meets-nginx-app/src/App.vue]
 2...
 3<v-timeline
 4    v-if="tasks.length > 0"
 5    dense
 6>
 7    <v-timeline-item
 8        v-for="(t, index) in tasks"
 9        :key="index"
10    >
11        <v-row class="display-1 text-capitalize">
12            <v-col cols="7">
13                {{ t }}
14            </v-col>
15            <v-col
16                class="text-right"
17                cols="5"
18            >
19                <v-btn
20                    icon
21                    @click="removeTask(index)"
22                >
23                    <v-icon color="red lighten-1" large>
24                        mdi-sticker-remove
25                    </v-icon>
26                </v-btn>
27            </v-col>
28        </v-row>
29    ...
30    </v-timeline-item>
31</v-timeline>

在您刚刚添加的代码中,v-btn组件的图标属性表示不需要任何文本。

@click组件事件将你的removeTask方法与按钮的点击事件联系起来,因此每次生成底层按钮点击事件时,都会调用你的方法。

您使用v-for循环提供的索引作为removeTask方法的参数。

最后,v-icon颜色将是red lighten-1,尺寸将是,您使用了mdi-sticker-remove材料设计的图标。

您现在已经更新了模板,使用了一些Vuetify组件,将其配置为使用和显示数据模型的内容,并允许应用程序的用户使用页面方法与它们进行交互。

以下是App.vue文件的最终代码:

  1[label vuetify-meets-nginx-app/src/App.vue]
  2<template>
  3    <v-app>
  4        <v-app-bar
  5            app
  6            color="primary"
  7            dark
  8        >
  9        <div class="d-flex align-center">
 10            <v-img
 11                alt="Vuetify Logo"
 12                class="shrink mr-2"
 13                contain
 14                src="https://cdn.vuetifyjs.com/images/logos/vuetify-logo-dark.png"
 15                transition="scale-transition"
 16                width="40"
 17            />
 18
 19            <v-img
 20                alt="Vuetify Name"
 21                class="shrink mt-1 hidden-sm-and-down"
 22                contain
 23                min-width="100"
 24                src="https://cdn.vuetifyjs.com/images/logos/vuetify-name-dark.png"
 25                width="100"
 26            />
 27        </div>
 28
 29        <v-spacer></v-spacer>
 30
 31        </v-app-bar>
 32
 33        <v-main>
 34            <v-container>
 35                <v-card elevation="0">
 36                    <v-card-title>
 37                        <v-text-field
 38                            v-model="newTask"
 39                            label="Task Name"
 40                            prepend-icon="mdi-content-save"
 41                            clear-icon="mdi-close-circle"
 42                            clearable
 43                            filled
 44                            type="text"
 45                            @click:prepend="addNewTask"
 46                            @click:clear="clearNewTask"
 47                        ></v-text-field>
 48                    </v-card-title>
 49                    <v-card-text>
 50                        <v-timeline
 51                            v-if="tasks.length > 0"
 52                            dense
 53                        >
 54                            <v-timeline-item
 55                                v-for="(t, index) in tasks"
 56                                :key="index"
 57                            >
 58                                <v-row class="display-1 text-capitalize">
 59                                    <v-col cols="7">
 60                                        {{ t }}
 61                                    </v-col>
 62                                    <v-col
 63                                        class="text-right"
 64                                        cols="5"
 65                                    >
 66                                        <v-btn
 67                                            icon
 68                                            @click="removeTask(index)"
 69                                        >
 70                                            <v-icon color="red lighten-1" large>
 71                                                mdi-sticker-remove
 72                                            </v-icon>
 73                                        </v-btn>
 74                                    </v-col>
 75                                </v-row>
 76                            </v-timeline-item>
 77                        </v-timeline>
 78                    </v-card-text>
 79                </v-card>
 80            </v-container>
 81        </v-main>
 82    </v-app>
 83</template>
 84
 85<script>
 86
 87export default {
 88    name: 'App',
 89
 90    data: () => ({
 91        tasks: ['task 1', 'task 2', 'task 3'],
 92        newTask: null
 93    }),
 94    methods: {
 95        addNewTask() {
 96            this.tasks.push(this.newTask);
 97            this.clearNewTask();
 98        },
 99        clearNewTask() {
100            this.newTask = '';
101        },
102        removeTask(i) {
103            this.tasks.splice(i, 1);
104        }
105    }
106};
107</script>

保存并关闭您的文件。

如果开发服务器尚未运行,请重新启动:

1npm run serve

现在您可以导航到localhost:8080,查看您的应用程序工作。

The Vuetify to-do app now displays three tasks in a list: Task 1, Task 2, Task 3

在此步骤中,您创建了一个要做的应用程序. 您添加了功能并更新了用户界面. 现在您已经编写了应用程序,您可以生成一个生产准备的版本。

步骤 4 – 构建您的生产应用程序

在之前的步骤中,你写了你的任务应用程序,但在使用Nginx发布之前,你需要为应用程序做好生产准备。

如果你试图在浏览器中打开你的src文件,你不会看到任何东西,这是因为它们是Vue.js文件,而不是HTML,JSCSS文件,这是浏览器可以读到的东西。

您可以使用构建命令自动执行此操作。package.json是您的应用程序的主要配置文件,它包含有关运行或构建应用程序的依赖和可用的命令的信息,例如如下文所示的构建命令:

 1[label package.json]
 2{
 3  ...
 4  "scripts": {
 5    "serve": "vue-cli-service serve",
 6    "build": "vue-cli-service build",
 7    "lint": "vue-cli-service lint"
 8  },
 9  ...
10}

有关package.json文件配置的更多信息,请参阅package.json指南。

要启动构建过程,请用CTRL+C停止 dev 服务器。

在相同的终端中,导航到项目目录:

1cd vuetify-meets-nginx-app

运行构建命令:

1npm run build

当构建完成时,您将在dist目录中为生产准备一个应用程序版本。

接下来,您将设置 Nginx 作为反向代理来部署和访问应用程序。

步骤 5 — 将 Nginx 配置为反向代理

现在你有一个工作应用程序,你必须将 Nginx 配置为反向代理来服务你的应用程序的文件,并将其连接到你的域名。

一个 reverse proxy 是一个应用程序或服务,在服务器上运行并将外部请求发送到另一个位置. 在您的情况下,每次用户在浏览器中访问您的域,Nginx 都会通过从您的应用程序中回复一个文件来处理这个请求。

「Nginx」與「Sites」合作,每個網站都是一個不同的網站,配置為單一檔案,所有配置檔案都預設在「/etc/nginx/sites-available/」中。

1cd /etc/nginx/sites-available/

创建一个名为vuetify-meets-nginx-app的文件:

1sudo nano vuetify-meets-nginx-app

<$>[注] **注:**您可以随意命名该文件,但将其命名为您想要发布的应用程序或网站是惯例。

在您的vuetify-meets-nginx-app文件中,添加以下行,确保您用自己的信息更新server_name:

1[label /etc/nginx/sites-available/vuetify-meets-nginx-app]
2server {
3  listen 80;
4  listen [::]:80;
5  server_name your_domain;
6  autoindex on;
7  root   /home/sammy/vuetify-meets-nginx-app/dist/;
8  index index.html;
9}

在本教程中,你正在配置Nginx来聆听端口80,但你可以使用任何你想要的端口. 用你的域名替换your_domain

使用root行,你会告诉 Nginx 所有的文件都在前一步创建的 /home/sammy/vuetify-meets-nginx-app/dist/ 目录中。

保存并关闭您的文件。

接下来,您需要解决 Nginx 配置文件中的权限问题。

「Nginx」是一個在您的伺服器上執行的服務,您可以用以下命令列出與 Nginx 相關的所有執行流程:

1ps -fea | grep nginx

带有-fea旗的ps命令列出了完整格式列表中的所有当前流程,然后将该命令的输出过滤到仅与nginx匹配的列表流程。

结果将类似于以下:

1[secondary_label Output]
2root 39922 1 0 Jul14 ?        00:00:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
3www-data 39923 39922 0 Jul14 ?        00:00:01 nginx: worker process
4sammy 117909 117434 0 21:27 pts/0 00:00:00 grep --color=auto nginx

正如输出所示,nginx服务正在与用户www-data运行。

接下来,使用此命令检查 /home/sammy/vuetify-meets-nginx-app/dist/ 的权限:

1ls -l /home/sammy/vuetify-meets-nginx-app/dist/

结果将类似于以下:

1[secondary_label Output]
2total 20
3drwxrwxr-x 2 sammy sammy 4096 Jul 14 18:54 css
4-rw-rw-r-- 1 sammy sammy 4286 Jul 14 18:54 favicon.ico
5-rw-rw-r-- 1 sammy sammy 853 Jul 14 18:54 index.html
6drwxrwxr-x 2 sammy sammy 4096 Jul 14 18:54 js

所有文件和文件夹都有权限可用于用户sammy。如果您将Nginx配置为读取这些文件,它将无法工作,因为 Nginx用户www-data没有执行权限。

有几种方法来解决这个问题:

  • 授予 Nginx 閱讀、寫入和執行權限至「dist」文件夾. 然而,授予一個可以從整個網絡取得閱讀本地使用者檔案的權限的服務並不安全。 此外, Nginx 將需要獲得所有母文件夾的存取權限,因為它需要移動到最終文件夾,這基本上會向世界開啟「/home」目錄。 這是不建議的
  • 使用「sudo」來執行「nginx」。 這也不是安全的,因為現在你將有一個服務,可以存取您的伺服器上的所有檔案
  • 將你的「dist」內容移至一個只有 Nginx 可以存取的位置,而沒有其他人。

对于本教程,您将使用第三种选项。

在Ubuntu和其他一些基于Linux的发行版中,服务之间交换文件的共享场所是/var路径,你会将文件复制到/var/www,这是Nginx用于网站的默认路径。

从项目目录中运行以下命令来复制文件到 /var/www 路径:

1sudo cp -r /home/sammy/vuetify-meets-nginx-app/dist /var/www/vuetify-meets-nginx-app

所有文件都将以与之前相同的权限复制,这适用于sammy用户,因此您需要将sammy用户添加到同一权限组为www-data

1sudo usermod -aG www-data sammy

此时,Nginx可以以安全的方式访问所需的文件,但是,您需要每次生成新版本的应用程序来复制项目文件,这会使自动部署、CI/CD 工具等等变得复杂。

要做到这一点,打开package.json进行编辑,并添加突出的文本:

1[label package.json]
2...
3"build": "vue-cli-service build --dest /var/www/vuetify-meets-nginx-app",
4...

保存并关闭您的文件。

现在您可以完成 Nginx 配置,打开 Nginx 配置文件并使用新的应用路径更新它:

1[label /etc/nginx/sites-available/vuetify-meets-nginx-app]
2server {
3  listen 80;
4  listen [::]:80;
5  server_name your_domain OR your_server_IP;
6  autoindex on;
7  root   /var/www/vuetify-meets-nginx-app;
8  index index.html;
9}

保存并关闭您的文件。

现在您的网站文件已经准备好了,您需要启用它。

1cd /etc/nginx/sites-enabled/

禁用默认网站,以确保您没有两个网站启用并在同一端口(端口 80)上收听:

1sudo rm default

最后,创建一个simlink文件到您的应用程序的配置文件:

1sudo ln -s /etc/nginx/sites-available/vuetify-meets-nginx-app

Nginx 只会考虑在启用目录中放置的网站文件. 您可以直接复制配置文件,但不建议复制文件,因为您可能存在差异。

测试以确保您的 Nginx 文件没有语法错误:

1sudo nginx -t

你的输出将看起来像这样:

1[secondary_label Output]
2nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
3nginx: configuration file /etc/nginx/nginx.conf test is
4successful

若要应用这些更改,请重新启动 Nginx 服务:

1sudo systemctl restart nginx

现在你可以导航到你的域(或你的服务器的IP地址)查看你的任务应用程序准备和发布。

The Vuetify to-do app displays three tasks in a list: Task 1, Task 2, Task 3

在此步骤中,您将 Nginx 配置为反向代理来发布您的应用程序。

结论

在本教程中,您创建了一个 Vue.js 应用程序,并安装并配置了 Vuetify。

要更仔细地查看项目文件,请参阅 Github 存储库

作为下一步,尝试配置 Nginx 以在 HTTPS 上服务您的应用程序. 要开始,请遵循我们的教程, How To Secure Nginx with Let's Encrypt on Ubuntu 20.04

要了解有关 Vuetify 的更多信息,请参阅 Vuetify 文档。 如果您对扩展 Vuetify 组件的功能感兴趣,请参阅我们的教程, 扩展 Vuetify 表单字段验证

Published At
Categories with 技术
comments powered by Disqus