In the development of the VUE project, the need to create a route to the specified directory file configuration, if it is only a small project may be ok, but if it is a large project, this may seem boring and tedious, is there a way to simplify the route configuration? For example, the nuxt.js server automatically generates the routing configuration of the VUe-Router module based on the Pages directory structure. Next, I will show you how to automate routing in non-server rendering.
For the convenience of explanation, the following example content is based on vecli4 scaffolding. This article function source address: github.com/zhicaizhu12… .
Implementation approach
- routing
component
It can be created automatically based on the directory structure. - Routing meta information
meta
And other routing information is used in the routing configuration fileCustom Blocks (custom-blocks)Contains user-defined route configuration information, for examplemeta
, whether the route is loaded on demand and other information if the file does not contain changesThe custom blockIs not automatically generated routing configuration. In this article, the custom block isz-route
, in which to customize the required routing information:
< z - the route > {" dynamic ": true," meta ": {" title" : "home page", "icon" : "el - icon - plus", "auth" : "homepage",... } } </z-route>Copy the code
- Embedded routines by
For nested routing, you can define a template file in the current directory of the file you want to configure as a child routing, which in this case is_layout.vue
, there is only one template that defines nested routinesrouter-view
Labels, such as:
<! -- _layout. Vue - > < template > < div > < p > the parent page content < / p > < the router - the view > < / router - the view > < / div > < / template >Copy the code
- Dynamic route configuration This section describes how to configure routes dynamically
/user/:id?
, can be created by_id.vue
or_id/index.vue
File implementation, for example.
. |-- user |-- _id.vue ...Copy the code
- Routing path
path
According to the file directory structure created under the specified project folder as the access path of the route, this article specifies isviews
Folders, such as file directories, are shown below.
|-- views
|-- _layout.vue
|-- homepage.vue
|-- system
|-- user
|-- index.vue
|-- _id.vue
Copy the code
Based on the above directories, the expected generated path is as follows
{
path: '/'. children: [ {path: '/homepage'. }, {path: '/user'. children:[ {path: ':id? '. }]}]}Copy the code
Based on the above implementation ideas, we need to obtain and parse vUE file directory structure and file content information, and automatically generate the required routing configuration information according to the parsed information. Therefore, we need to use the function of Webpack plug-in and VUe-template-Compiler to parse VUE files. No matter adding, deleting or modifying files, routing information can be monitored and automatically updated. Next we’ll show you how to use WebPack to write a plug-in and get and generate a routing configuration file.
Function implementation
The WebPack plug-in consists of:
- A JavaScript naming function.
- Define one on the prototype of the plug-in function
apply
Methods.- Specifies an event hook bound to WebPack itself.
- Handles specific data for webPack internal instances.
- The callback provided by WebPack is invoked when the functionality is complete.
// a JavaScript naming function.
function MyExampleWebpackPlugin() {};// Define a 'apply' method on the prototype of the plug-in function.
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
// Specify an event hook to mount to webpack itself.
compiler.plugin('webpacksEventHook'.function(compilation /* Handle specific data for webpack internal instances. * /, callback) {
console.log("This is an example plugin!!!");
// Call the webPack callback when the function is complete.
callback();
});
};
Copy the code
There are many wepack event hooks. If you need them, you can go to the official webpack document for reference. In this article, the code of automatic routing Webpack plug-in is as follows:
class AutoRoutingPlugin {
constructor(private options: Options) { }
apply(compiler: Compiler) {
// Update the route configuration
const generate = (a)= > {
const code = generateRoutes(this.options)
const to = this1. Options routePath? path.join(process.cwd(),this. The options. RoutePath) : path. The join (__dirname,'./routes.js')
if (
fs.existsSync(to) &&
fs.readFileSync(to, 'utf8').trim() === code.trim()
) {
return
}
fs.writeFileSync(to, code)
}
let watcher: any = null
// After setting up the initial plug-in, execute the plug-in
compiler.hooks.afterPlugins.tap(pluginName, () => {
generate()
})
// execute before generating resources to the output directory
compiler.hooks.emit.tap(pluginName, () => {
const chokidar = require('chokidar')
watcher = chokidar.watch(path.join(process.cwd(), this.options.pages || 'src/views'), {
persistent: true,
}).on('change', () => {
generate()
});
})
// Listening mode stops execution
compiler.hooks.watchClose.tap(pluginName, () => {
if (watcher) {
watcher.close()
watcher = null}}}})Copy the code
AfterPlugins are initialized, a route configuration file is automatically generated at first startup. Then, we listen for changes in the folder files that need to be configured before generating resources to the output directory. The generateRoutes method updates the route configuration file if a change is detected. The generateRoutes method generates the route configuration information and writes it to a file in the specified directory.
export function generateRoutes({
pages = 'src/views',
importPrefix = '@/views/',
dynamic = true, //Whether chunkNamePrefix = needs to be loaded on demand' ',
layout = '_layout.vue',
}: GenerateConfig) :string {
// Specify that the file does not need to generate a routing configuration
const patterns = ['**/*.vue'.`! * * /${layout}`]
// Get file paths for all layouts
const layoutPaths = fg.sync(` * * /${layout}`, {
cwd: pages,
onlyFiles: true,})// Get all file paths that need routing configuration
const pagePaths = fg.sync(patterns, {
cwd: pages,
onlyFiles: true,})// Get route configuration information
const metaList = resolveRoutePaths(
layoutPaths,
pagePaths,
importPrefix,
layout,
(file) => {
return fs.readFileSync(path.join(pages, file), 'utf8')})// Returns what needs to be written to the routing file
return createRoutes(metaList, dynamic, chunkNamePrefix)
}
Copy the code
As you can see from the above code, we first need to get the template file and the path of the file to configure the route, and then the resolveRoutePaths method uses this information to get further information about the route. So what does the resolveRoutePaths method do?
export function resolveRoutePaths( layoutPaths: string[], paths: string[], importPrefix: string, layout: string, readFile: (path: string) => string ): PageMeta[] { const map: NestedMap<string[]> = {} // splitedLayouts = layoutpaths.map ((p) => p.split('/')) const hasRootLayout = splitedLayouts. Some (item => item.length === = 1) if (hasRootLayout) { ForEach ((path) => {let dir = path.slice(0, path.length-1) // Dir. Unshift (rootPathLayoutName) setToMap(map, pathToMapPath(dir), ForEach ((path) => {setToMap(map, pathToMapPath(path.slice(0, path.length - 1)), path) }) } const splitted = paths.map((p) => p.split('/')) splitted.forEach((path) => { if (hasRouteBlock(path, ReadFile)) {// Check whether there is a custom block, Let dir = path if (hasRootLayout) {// If there is a root template file, insert the template path dir.unshift(rootPathLayoutName)} // SetToMap (map, pathToMapPath(dir), path)}}) return pathMapToMeta(map, importPrefix, readFile, 0, importPrefix) Function getRouteBlock(path: string[], readFile: (path: String) => string) {const content = readFile(path.join('/')) const parsed = parseComponent(content, { pad: 'space', Return parsed.customblocks. Find ((b) => b.type === routeBlockName)} // Whether there is a custom block function hasRouteBlock(path: string[], readFile: (path: string) => string) { const routeBlock = getRouteBlock(path, readFile) return routeBlock && tryParseCustomBlock(routeBlock.content, path, Function pathMapToMeta(map: NestedMap<string[]>, importPrefix: string, readFile: (path: string) => string, parentDepth: number = 0, layout: string, ): PageMeta[] { if (map.value) { const path = map.value if (path[0] === rootPathLayoutName) { path.shift() } ... Const routeBlock = getRouteBlock(path, readFile) if (routeBlock) { Route = tryParseCustomBlock(routeblock. content, path, routeBlockName)}... return [meta] } ... }...Copy the code
There are no implementation details from the above code, but we can get a general idea. We first get the template file path information, then use setToMap to generate a mapping from this information, and then process the non-template files that need to be configured as routes. Similarly, the setToMap method generates a mapping relationship based on their path information. The getRouteBlock and tryParseCustomBlock methods parse the custom block information for each file. Finally, the mapping relationship and the custom block information are combined to generate the desired route configuration information. You can view the detailed implementation in z-auto-route.
The actual project uses the configuration
Add a Z-route label to the header of the VUE file to generate a route. The content in the header is in JSON format
< z - the route > {" dynamic ": false," meta ": {" title" : "root page layout"}} < / z - the route >Copy the code
Dynamic indicates whether the route is loaded on demand. If this parameter is not set, the dynamic parameter is used globally. Note:
- If there is no
z-route
Tag indicates that the page does not generate routes - Only supported for now
meta
anddynamic
Two Settings. - If you need
z-route
The label is highlighted and can be setvs-code
的settings.json
"vetur.grammar.customBlocks": {
"z-route": "json"
}
Copy the code
Run the vscode command
Vetur: Generate grammar from vetur.grammar.customBlocks
Copy the code
Webpack configuration
Configure the content in the weppack configuration file. The following is the configuration information of vue.config.js
// vue.config.js
const ZAutoRoute = require('z-auto-route/lib/webpack-plugin')... configureWebpack:(config) = > {
config.plugins = [
...config.plugins,
new ZAutoRoute({
pages: 'src/views'.// Route page file address, default is' SRC /views'
importPrefix: '@/views/'.// import prefix directory to import page files. Default is '@/views/'.}}),]...Copy the code
Routing File Configuration
// Initialize route import Vue from'vue'
import VueRouter from 'vue-router'
import routes from 'z-auto-route'Vue.use(VueRouter) // Configure additional information based on the project, such as generating menu information based on the route //... const router = new VueRouter({ mode:'history',
base: process.env.BASE_URL,
routes,
})
export default router
Copy the code
Instance Project Directory
| - views | -- _layout. Vue / / global layout components | -- homepage. Vue / / homepage | | - system / / system management -- _layout. Vue / / embedded routines by | - role / / role management | - index. Vue | | - user / / the user management, the index | - _id / / user details | -- index. VueCopy the code
Generating a Routing Structure
import _layout from '@/views/_layout.vue'
function system__layout() {
return import(
/* webpackChunkName: "system-layout"* /'@/views/system/_layout.vue')}function system_role_index() {
return import(
/* webpackChunkName: "system-role-index"* /'@/views/system/role/index.vue')}function system_user_index() {
return import(
/* webpackChunkName: "system-user-index"* /'@/views/system/user/index.vue')}function system_user__id_index() {
return import(
/* webpackChunkName: "system-user-id-index"* /'@/views/system/user/_id/index.vue'
)
}
import homepage from '@/views/homepage.vue'
export default [
{
name: 'layout',
path: '/',
component: _layout,
meta: {
title: 'Layout Components',
hide: true
},
dynamic: false,
children: [
{
name: 'system-layout',
path: '/system',
component: system__layout,
meta: {
title: 'System Administration'
},
sortIndex: 0,
children: [
{
name: 'system-role',
path: 'role',
component: system_role_index,
meta: {
title: 'Role Management'
}
},
{
name: 'system-user',
path: 'user',
component: system_user_index,
meta: {
title: 'User Management'
}
},
{
name: 'system-user-id',
path: 'user/:id',
component: system_user__id_index,
meta: {
title: 'User Details',
hide: true
}
}
]
},
{
name: 'homepage',
path: '/homepage',
component: homepage,
meta: {
title: 'home'
},
dynamic: false,
sortIndex: -1
}
]
}
]
Copy the code
Project renderings
Reference source
vue-auto-routing
conclusion
If there are any errors in this article, please correct them in the comments section. If the content of this article can improve the development efficiency of students in the project, please like and follow. Source address: github.com/zhicaizhu12… .