Skip to content

Commit 97343c7

Browse files
committed
docs: add more details in README.md and add validation composable
1 parent 3a6cb13 commit 97343c7

File tree

9 files changed

+312
-41
lines changed

9 files changed

+312
-41
lines changed

README.md

+203-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## Build Setup
44

55
```bash
6+
# prepare configurations
7+
$ yarn prepare
8+
69
# install dependencies
710
$ yarn install
811

@@ -23,36 +26,220 @@ For detailed explanation on how things work, check out the [documentation](https
2326

2427
You can create the following extra directories, some of which have special behaviors. Only `pages` is required; you can delete them if you don't want to use their functionality.
2528

26-
### `assets`
29+
### `components`
2730

28-
The assets directory contains your uncompiled assets such as Stylus or Sass files, images, or fonts.
31+
The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components.
2932

30-
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/assets).
33+
#### `components/base`
3134

32-
### `components`
35+
Components in this directory will be registered globally automatically by this configuration in `nuxt.config.js`:
3336

34-
The components directory contains your Vue.js components. Components make up the different parts of your page and can be reused and imported into your pages, layouts and even other components.
37+
```javascript
38+
components: [
39+
{ path: '@/components/base/' },
40+
],
41+
```
42+
43+
#### `components/layout`
3544

36-
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/components).
45+
The directory to store your common layout component, such as `Navbar`, `Sidebar`, `Header`, `Footer`, `etc`
3746

38-
### `layouts`
47+
#### `components/*`
48+
49+
Place your modules' components, good naming pratice should be something like:
50+
51+
```javascript
52+
// components/products/Chart.vue
53+
// components/blogs/BlogItem.vue
54+
```
55+
56+
### `constants`
57+
58+
This directory should should contains your project's constants, enums Javascript doesn't support `ENUM` type so we can use `Object.freeze()` to create a true ENUM object.
59+
60+
### `core/config`
61+
62+
Our plugins' configuration should be in here, the `nuxt.config.js` file or in special dedicated files like `.eslintrc.js`, `.prettierrc.js`
63+
64+
### `core/layouts`
3965

4066
Layouts are a great help when you want to change the look and feel of your Nuxt app, whether you want to include a sidebar or have distinct layouts for mobile and desktop.
4167

4268
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/layouts).
4369

70+
### `core/middleware`
71+
72+
The middleware directory contains your application middleware. Middleware lets you define custom functions that can be run before rendering either a page or a group of pages (layout).
73+
74+
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/middleware).
75+
76+
### `core/mixins`
77+
78+
This folder contains Vue mixins
79+
80+
We can declare a global mixin with:
81+
82+
```javascript
83+
import Vue from 'vue';
84+
85+
Vue.mixin({
86+
created() {
87+
var myOption = this.$options.myOption;
88+
if (myOption) {
89+
console.log(myOption);
90+
}
91+
},
92+
});
93+
```
94+
95+
and import it as a plugin in `nuxt.config.js` or simple export an on-demand mixin in here:
96+
97+
```javascript
98+
export const myHelpfulMixin = {
99+
created() {
100+
var myOption = this.$options.myOption;
101+
if (myOption) {
102+
console.log(myOption);
103+
}
104+
},
105+
};
106+
```
107+
108+
### `core/plugins`
109+
110+
The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`.
111+
112+
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/plugins).
113+
114+
### `core/styles`
115+
116+
This folder contains `css` and `scss` files, scss files, `variables`, `mixins` and `functions` also got imported to the project globally by using this configuration in `nuxt.config.js`:
117+
118+
```javascript
119+
buildModules: [
120+
// https://www.npmjs.com/package/@nuxtjs/style-resources
121+
'@nuxtjs/style-resources',
122+
],
123+
124+
styleResources: {
125+
scss: [
126+
'@/core/styles/scss/_colors.scss',
127+
'@/core/styles/scss/_mixins.scss',
128+
'@/core/styles/scss/_variables.scss',
129+
],
130+
hoistUseStatements: true,
131+
},
132+
```
133+
134+
### `core/use`
135+
136+
This directory contains composables files for `composition API` For more information about Vue composition API, please check out the [Vue composition API documentation](https://v3.vuejs.org/guide/composition-api-introduction.html)
137+
138+
Notes:
139+
140+
- Yes, you can ignore Composition API if you like the original option API better.
141+
142+
```javascript
143+
// Option API component:
144+
export default {
145+
data() {
146+
return {
147+
blogs: 123,
148+
categories: 456,
149+
}
150+
},
151+
created() {},
152+
mounted() {},
153+
}
154+
155+
// Composition API
156+
export default {
157+
setup(props, context) {
158+
// No created hook, setup runs in server-side
159+
const dataBlog = reactive({
160+
blogs: 123,
161+
})
162+
163+
const dataCategory = reactive({
164+
categories: 456,
165+
})
166+
167+
onMounted(() => {
168+
// Do stuff when component mounted
169+
})
170+
171+
return {
172+
dataBlog,
173+
dataCategory,
174+
}
175+
}
176+
}
177+
```
178+
179+
- Vue 2 and Vue 3 Composition API are "almost" the same.
180+
- Nuxt has supercharged Vue Composition API with some cooler features, see [the documentation](https://composition-api.nuxtjs.org/getting-started/introduction).
181+
182+
### `core/utils`
183+
184+
This directory contains your helper functions, global mixins, global dicrectives and global filters
185+
186+
`/directives`, `/mixins` and `/filters` are automatically registered using Webpack's `require.context()`.
187+
188+
Files in `/functions` are imported manually when use to keep the type annotation
189+
190+
### `locale`
191+
192+
This directory contains your global localization and will be imported into `nuxt.config.js`. We're using `YAML` file because it has better syntax than `JSON`
193+
194+
Notes: We translate the website on the go by adding localization on component-level
195+
196+
```html
197+
<template>
198+
<h1>{{ $t('Home page') }}</h1>
199+
</template>
200+
201+
<script>
202+
import { useContext } from '@nuxtjs/composition-api';
203+
export default {
204+
// Composition API
205+
setup() {
206+
const { i18n } = useContext();
207+
208+
console.log(i18n.t('Hello world!'));
209+
},
210+
211+
// Option API
212+
mounted() {
213+
console.log(this.$t('Hello world!'));
214+
},
215+
};
216+
</script>
217+
218+
<i18n lang="yaml">
219+
vi: Home page: Trang chủ Hello world!: Xin chào thế giới! Change language: Đổi
220+
ngôn ngữ
221+
</i18n>
222+
```
44223

45224
### `pages`
46225

47226
This directory contains your application views and routes. Nuxt will read all the `*.vue` files inside this directory and setup Vue Router automatically.
48227

49228
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/get-started/routing).
50229

51-
### `plugins`
230+
### `server/routes`
52231

53-
The plugins directory contains JavaScript plugins that you want to run before instantiating the root Vue.js Application. This is the place to add Vue plugins and to inject functions or constants. Every time you need to use `Vue.use()`, you should create a file in `plugins/` and add its path to plugins in `nuxt.config.js`.
232+
This directory contains files to declare API routes so you can call your Backend API from the Frontend server and hide your actual API endpoint
54233

55-
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/plugins).
234+
This using Nuxt.js server middleware and added in `nuxt.config.js`:
235+
236+
```javascript
237+
serverMiddleware: [
238+
{ path: '/api/v1', handler: '@/server' },
239+
],
240+
```
241+
242+
Read more about Nuxt.js server middleware in [the documentation](https://nuxtjs.org/docs/2.x/configuration-glossary/configuration-servermiddleware).
56243

57244
### `static`
58245

@@ -67,3 +254,9 @@ More information about the usage of this directory in [the documentation](https:
67254
This directory contains your Vuex store files. Creating a file in this directory automatically activates Vuex.
68255

69256
More information about the usage of this directory in [the documentation](https://nuxtjs.org/docs/2.x/directory-structure/store).
257+
258+
### `store-lazy`
259+
260+
This directory contains your dynamic modules for Vuex.
261+
262+
See more information about Vue Dynamic module registeration in [the documentation](https://vuex.vuejs.org/guide/modules.html#dynamic-module-registration).

aliases.config.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,15 @@ const prettier = require('prettier');
66

77
const aliases = {
88
'@': '.',
9-
'~': '.',
109
'@@': '.',
11-
'~~': '.',
1210
'@core': './core',
1311
'@services': './services',
1412
'@components': './components',
1513
'@constants': './constants',
1614
'@store': './store',
1715
'@apis': './core/apis',
1816
'@mixins': './core/mixins',
17+
'@use': './core/use',
1918
'@utils': './core/utils',
2019
};
2120

constants/validation.js

+18-5
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,26 @@ export const VALIDATION_TYPE = Object.freeze({
44
PHONE: 3,
55
ALPHA: 4,
66
NUMBER: 5,
7+
URL: 6,
78
});
89

910
// Wrap with i18n
1011
export const VALIDATION_MESSAGE = Object.freeze({
11-
[VALIDATION_TYPE.REQUIRED]: 'validate.required',
12-
[VALIDATION_TYPE.EMAIL]: 'validate.email',
13-
[VALIDATION_TYPE.PHONE]: 'validate.phone',
14-
[VALIDATION_TYPE.ALPHA]: 'validate.alpha',
15-
[VALIDATION_TYPE.NUMBER]: 'validate.number',
12+
REQUIRED: 'This field is required',
13+
EMAIL: 'This field must be a valid email',
14+
PHONE: 'This field must be a valid phone number',
15+
ALPHA: 'This field can only contain words and spaces',
16+
TEXT: 'This field cannot contain special letters',
17+
NUMBER: 'This field must be a number',
18+
URL: 'This field must be a valid url',
1619
});
20+
21+
export const VALIDATION_REGEX = Object.freeze({
22+
EMAIL: /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/g,
23+
PHONE: /^\s*(?:\+?(\d{1,3}))?([-. (]*(\d{3})[-. )]*)?((\d{3})[-. ]*(\d{2,4})(?:[-.x ]*(\d+))?)\s*$/gm,
24+
ALPHA: /^[A-Za-z ]*$/g,
25+
TEXT: /^[A-Za-z0-9-_ ]*$/g,
26+
NUMBER: /^[0-9]*$/g,
27+
URL: /^(https?:\/\/)?([\da-z.-]+\.[a-z.]{2,6}|[\d.]+)([/:?=&#]{1}[\da-z.-]+)*[/?]?$/g,
28+
});
29+

core/use/validation.js

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { useContext } from '@nuxtjs/composition-api';
2+
import { VALIDATION_MESSAGE, VALIDATION_REGEX, VALIDATION_TYPE } from '@/constants/validation';
3+
4+
export const useValidation = () => {
5+
const { i18n } = useContext();
6+
7+
// https://github.com/yiminghe/async-validator#validator
8+
// Use with: <el-form-item :rules="[rules.required, rules.email]">...
9+
const rules = {
10+
required: {
11+
required: true,
12+
message: i18n.t(VALIDATION_MESSAGE.REQUIRED)
13+
},
14+
email: {
15+
trigger: ['change'],
16+
validator: (rule, value, callback) => {
17+
if (!value) {
18+
callback(new Error(i18n.t(VALIDATION_MESSAGE.REQUIRED)));
19+
} else if (!VALIDATION_REGEX.EMAIL.test(value)) {
20+
callback(new Error(i18n.t(VALIDATION_MESSAGE.EMAIL)));
21+
}
22+
},
23+
},
24+
phone: {
25+
trigger: ['change'],
26+
validator: (rule, value, callback) => {
27+
if (!value) {
28+
callback(new Error(i18n.t(VALIDATION_MESSAGE.REQUIRED)));
29+
} else if (!VALIDATION_REGEX.PHONE.test(value)) {
30+
callback(new Error(i18n.t(VALIDATION_MESSAGE.PHONE)));
31+
}
32+
},
33+
},
34+
alpha: {
35+
trigger: ['change'],
36+
validator: (rule, value, callback) => {
37+
if (!value) {
38+
callback(new Error(i18n.t(VALIDATION_MESSAGE.REQUIRED)));
39+
} else if (!VALIDATION_REGEX.ALPHA.test(value)) {
40+
callback(new Error(i18n.t(VALIDATION_MESSAGE.ALPHA)));
41+
}
42+
},
43+
},
44+
number: {
45+
trigger: ['change'],
46+
validator: (rule, value, callback) => {
47+
if (!value) {
48+
callback(new Error(i18n.t(VALIDATION_MESSAGE.REQUIRED)));
49+
} else if (!VALIDATION_REGEX.NUMBER.test(value)) {
50+
callback(new Error(i18n.t(VALIDATION_MESSAGE.NUMBER)));
51+
}
52+
},
53+
},
54+
url: {
55+
trigger: ['change'],
56+
validator: (rule, value, callback) => {
57+
if (!value) {
58+
callback(new Error(i18n.t(VALIDATION_MESSAGE.REQUIRED)));
59+
} else if (!VALIDATION_REGEX.URL.test(value)) {
60+
callback(new Error(i18n.t(VALIDATION_MESSAGE.URL)));
61+
}
62+
},
63+
},
64+
};
65+
66+
return { rules, VALIDATION_TYPE };
67+
};

0 commit comments

Comments
 (0)