I met
Front End time read an article on nuggets and learned about the require.context API. After doing some research on this API, I had an idea to duplicate nuxtJS routing rules with require.context. The routing code of NuxtJS is simply read, and it is found that gulp and global are used to monitor the changes of files under pages folder, and then compile into the corresponding route (not deep understanding, Context is used to import file modules directly from the XX folder.
require.context(path: string, deep? : boolean, filter? :RegExp, mode? :"sync" | "eager" | "weak" | "lazy" | "lazy-once")
Copy the code
This is how the API is used. Assume that there are @/pages/A/index.vue and @/pages/B/ b. vue in the pages folder of the project. So if you introduce it this way you get the following result.
const context = require.context("@/pages/".true./\.vue/)
===>
context = webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
Copy the code
You can get the file path if you call the context keys method.
const pages = context.keys()
===>
pages = ["./A/A.vue"."./B/B.vue"]
Copy the code
If you want to introduce the page module, you just need to
const pageModule = context("./A/A.vue")
===>
pageModule = Module {default: {... },__esModule: true.Symbol(Symbol.toStringTag): "Module"}
Copy the code
The pageModule, the pageModule, is written in the component of the vue-router route.
imagination
With this in mind, I came up with the nuxTJS route import method, but I felt. Assigning routing rules to folder nesting makes the whole file relationship very confusing. It’s not very neat, and if every file has an index. CSS in addition it would be a huge headache to maintain the project. So I’m going to flatten the page into one level. This is a neat way to wrap the routing of a page into a JSON file. In this way, the entire route relationship is also obvious in the JSON file.
implementation
When you have an idea, put it into practice. First read the VUE file module
const context = require.context("@/pages/".true./\.vue/)
Copy the code
Create the JSON file. In addition, the routing relationship is written and imported.
// routeHierarchyMap.json
{
"/": {},
"A": {},
"B": {}}Copy the code
And then the route is parsed, and I’m thinking level by level, because the route might have multiple children. First, import the route into an object, whose key-value result is as follows:
const pageObj = {
"/": Module,
"A": Module,
"B": Module
}
Copy the code
// routes indicates the route mapping of the JSON file
function getRouteFromObj(routes, parentsRoute) {
const routesMap = Object.keys(routes);
return routesMap.map((item) = > {
const path = `${parentsRoute.replace(/ / / $/."")}/${item.replace(/ / / $/."")}`;
return {
path,
component: () = > pageObj[item].component,
children: getRouteFromObj(routes[item], path),
name: "",}}); }Copy the code
call
import routeMapData from "routeHierarchyMap.json"
getRouteFromObj(routeMapData, "")
// Get the route as follows= = = > [{path: "/A".component: () = > Module,
children: [].name: ""
},
{
path: "/B".component: () = > Module,
children: [].name: ""}]Copy the code
If there are nested relationships, for example:
// routeHierarchyMap.json
{
"/": {
"A": {
"B": {}}}}Copy the code
// Get the route as follows[{path: "/".name: "Home".component: () = > Module,
children: [{path: "/A".component: () = > Module,
children: [{path: "/B".component: () = > Module,
children: [].name: ""}].name: ""}}]]Copy the code
In addition, there may be some personalized routing rules, such as writing needLogin or name values in mate, etc. So add a __meta to the JSON of the route map to hold the personalized configuration as follows:
// routeHierarchyMap.json
{
"/": {
"__meta": {
"name": "home"}},"A": {
"__meta": {
"name": "a"."meta": {
"needLogin": true}}},"B": {
"__meta": {
"name": "b"}}}Copy the code
The function that resolves the route needs further optimization
// routes indicates the route mapping of the JSON file
function getRouteFromObj(routes, parentsRoute) {
// Remove key from "__meta"
const routesMap = Object.keys(routes).filter((item) = >item ! = ="__meta");
return routesMap.map((item) = > {
const path = `${parentsRoute.replace(/ / / $/."")}/${item.replace(/ / / $/."")}`;
return {
path,
component: () = > pageObj[item].component,
children: getRouteFromObj(routes[item], path),
// Add other attributes. routes[item].__meta, } }); }Copy the code
Ok, so we have implemented import based on JSON route mapping, but so far, just a modification of the routes notation to simplify the import step, so how to make this automatic? If you rely on the above, I can think of automated production pages that rely on scripts and automated write route mapping. Just like hexo, to create a post I just need hexo create
redesign
The disadvantage of relying on the route mapping file is that it is too cumbersome. It simplifies the original step by a small step, but increases the cost of its use, which is not a friendly measure for developers. Therefore, nuxt.js route construction rules are referred to to reflect the relationship of real routes through the relationship of file routes.
Context is used to import modules. Modules are used to import modules. Since this method is entirely dependent on file path resolution, personalized meta processing cannot be performed.
function createRoutes(routeConfig) {
const { modules, redirect = "/" } = routeConfig;
// Routes at the end
const routes = [];
const pages = modules.keys();
for (const page of pages) {
// Parse the route of each vue file
addRoute(routes, page, modules);
}
/ / out
routes.push({
path: "/:pathMatch(.*)*",
redirect,
});
return routes;
}
Copy the code
A function that parses routes
function addRoute(routes, route, modules) {
// Current file path
const routeStr = route
.replace(/ ^ \ \ / /."")
.replace(/(\.\w+)$/."")
.replace(/^index/."home")
.replace(/\/index$/."");
// Route name
const name = routeStr.split("/").join("-").replace(/_/g."");
const path = routeStr.startsWith("home")? routeStr.replace(/^(home\/|home)/."/")
: "/" + routeStr;
// Parent route -findparent is the function to find the parent route
const target = findParent("/" + routeStr, name, routes);
// Parent routing path
consttargetFullPath = target? .meta? .fullPath ||"";
// Routing path
const finalPath = targetFullPath
? path.replace(String(targetFullPath), "")
: path;
// toProxy converts the routing object toProxy. Delete if children exist, delete the name field
const targetRoute = toProxy({
name,
path: finalPath.replace(/_/g.":") | |"/".// moduleResolve route parsing function
component: moduleResolve(modules(route)),
meta: {
originName: name,
fullPath: path,
},
});
if (target) {
constchildren = target? .children ?? []; target.children = [...children, targetRoute];return;
}
routes.push(targetRoute);
}
Copy the code
Route resolution
function moduleResolve(module) {
if (!module.default && module instanceof Promise) return () = > module;
if (module.default && module.__esModule) return module.default;
throw Error("Routing module resolution failed!");
}
Copy the code
To the Proxy
function toProxy(target) {
return new Proxy(target, {
set(target, p, value) {
if (p === "children") delete target.name;
return(target[p.toString()] = value); }}); }Copy the code
Search for the parent route
function findParent(route, name, routes, beforeTarget) {
const target = routes.find(
(item) = >
route.startsWith(item.path) &&
name.startsWith(String(item? .meta? .originName ||"")));constrouteRest = route.replace(target? .path ??""."");
if (target && routeRest.split("/").length === 2) return target;
if (target && routeRest)
return findParent(routeRest, name, target.children || [], target);
if (beforeTarget && routeRest) return beforeTarget;
return target;
}
Copy the code
Routes parsed in this mode are as follows: Refer to Nuxtjs for routing mode
The basic routing
pages/
--| user/
-----| index.vue
-----| one.vue
--| index.vue
Copy the code
router: {
routes: [{name: 'index'.path: '/'.component: 'pages/index.vue'
},
{
name: 'user'.path: '/user'.component: 'pages/user/index.vue'
},
{
name: 'user-one'.path: '/user/one'.component: 'pages/user/one.vue'}}]Copy the code
Dynamic routing
See Nuxtjs
Embedded routines by
See Nuxtjs
Dynamic nesting routines by
See Nuxtjs
conclusion
This is my study of require.context API and some thoughts. The former is a traversal and recursive generated route to a routing mapping object, and the latter is a parse generated route to a file path. Both perform generated routing at run time, which may have some impact on performance, and are not suitable for all scenarios.
Automatic register components, automatic register routes — lazy benefits (vUE, React) Reference: Nuxtjs
The role of require.context in webpack