Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ If you add some more information such as your thoughts and vision about the feat

Please refer to our [Contribution Guidelines](./CONTRIBUTING.md) and [Code of Conduct](./CODE_OF_CONDUCT.md).

## 🚀 The Future of EverShop

EverShop is seeing rapid organic growth and strong adoption from the developer community. We are now scaling our operations and building **EverShop Cloud**.

If you are a strategic investor interested in the future of Node.js commerce and our mission to set a new standard for modern eCommerce, we’d love to share our vision and roadmap with you.

📩 **Get in touch:** support@evershop.io

## License

[GPL-3.0 License](https://github.com/evershopcommerce/evershop/blob/main/LICENSE)
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/evershop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
"pg": "^8.16.3",
"postcss": "^8.4.18",
"postcss-loader": "^8.2.0",
"postcss-prefix-selector": "^2.1.1",
"prop-types": "^15.8.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ export function addDefaultMiddlewareFuncs(app) {
},
resave: getConfig('system.session.resave', false),
saveUninitialized: getConfig('system.session.saveUninitialized', true)
};
} as session.SessionOptions;

if (isProductionMode()) {
app.set('trust proxy', 1);
sess.cookie.secure = false;
sess.cookie!.secure = false;
}

const adminSessionMiddleware = session({
Expand Down Expand Up @@ -156,7 +156,7 @@ export function addDefaultMiddlewareFuncs(app) {
if (match) {
request.locals = request.locals || {};
request.locals.customParams = {};
const keys = [];
const keys: any[] = [];
pathToRegexp(r.path, keys);
keys.forEach((key, index) => {
request.locals.customParams[key.name] = match[index + 1];
Expand All @@ -182,10 +182,7 @@ export function addDefaultMiddlewareFuncs(app) {
return next();
}

const routes = getRoutes();
const route = findRoute(request);
request.locals = request.locals || {};
request.locals.webpackMatchedRoute = route;
if (!route || !isBuildRequired(route)) {
next();
} else {
Expand Down Expand Up @@ -222,100 +219,55 @@ export function addDefaultMiddlewareFuncs(app) {
path.join(theme.path, 'dist', '**', '[A-Z]*.js')
);
}
if (!route.webpackCompiler) {
route.webpackCompiler = webpack(
if (!app.locals.webpackCompiler) {
app.locals.webpackCompiler = webpack(
createConfigClient(
route,
route.isAdmin ? adminTailwindConfig : frontStoreTailwindConfig
)
adminTailwindConfig,
frontStoreTailwindConfig
) as any
);
}
const { webpackCompiler } = route;
const { webpackCompiler } = app.locals;
let middlewareFunc;
if (!route.webpackMiddleware) {
middlewareFunc = route.webpackMiddleware = middleware(webpackCompiler, {
serverSideRender: true,
publicPath: '/',
stats: 'none'
});
middlewareFunc.context.logger.info = () => {};
} else {
middlewareFunc = route.webpackMiddleware;
}
middlewareFunc.waitUntilValid(() => {
const { stats } = middlewareFunc.context;
const jsonWebpackStats = stats.toJson();
response.locals.jsonWebpackStats = jsonWebpackStats;
});
// We need to run build for notFound route
const notFoundRoute = routes.find((r) => r.id === 'notFound');
if (!notFoundRoute.webpackCompiler) {
notFoundRoute.webpackCompiler = webpack(
createConfigClient(notFoundRoute, frontStoreTailwindConfig)
);
}
const notFoundWebpackCompiler = notFoundRoute.webpackCompiler;
let notFoundMiddlewareFunc;
if (!notFoundRoute.webpackMiddleware) {
notFoundMiddlewareFunc = notFoundRoute.webpackMiddleware = middleware(
notFoundWebpackCompiler,
if (!app.locals.webpackMiddleware) {
middlewareFunc = app.locals.webpackMiddleware = middleware(
webpackCompiler,
{
serverSideRender: true,
publicPath: '/',
stats: 'none'
}
);
notFoundMiddlewareFunc.context.logger.info = () => {};
} else {
notFoundMiddlewareFunc = notFoundRoute.webpackMiddleware;
}

// We need to run build for adminNotFound route
const adminNotFoundRoute = routes.find((r) => r.id === 'adminNotFound');
if (!adminNotFoundRoute.webpackCompiler) {
adminNotFoundRoute.webpackCompiler = webpack(
createConfigClient(adminNotFoundRoute, adminTailwindConfig)
);
}
const adminNotFoundWebpackCompiler = adminNotFoundRoute.webpackCompiler;
let adminNotFoundMiddlewareFunc;
if (!adminNotFoundRoute.webpackMiddleware) {
adminNotFoundMiddlewareFunc = adminNotFoundRoute.webpackMiddleware =
middleware(adminNotFoundWebpackCompiler, {
serverSideRender: true,
publicPath: '/',
stats: 'none'
});
adminNotFoundMiddlewareFunc.context.logger.info = () => {};
middlewareFunc.context.logger.info = () => {};
} else {
adminNotFoundMiddlewareFunc = adminNotFoundRoute.webpackMiddleware;
middlewareFunc = app.locals.webpackMiddleware;
}

middlewareFunc(request, response, () => {
notFoundMiddlewareFunc(request, response, () => {
adminNotFoundMiddlewareFunc(request, response, next);
});
middlewareFunc.waitUntilValid(() => {
const { stats } = middlewareFunc.context;
const jsonWebpackStats = stats.toJson();
response.locals.jsonWebpackStats = jsonWebpackStats;
});

middlewareFunc(request, response, next);
}
});
app.use((request, response, next) => {
if (!isDevelopmentMode()) {
return next();
}
const routes = getRoutes();
const route = findRoute(request);
request.currentRoute = route;
if (!isBuildRequired(route)) {
return next();
}
if (!route.hotMiddleware) {
const { webpackCompiler } = route;
if (!app.locals.hotMiddleware) {
const { webpackCompiler } = app.locals;
const hotMiddleware = webpackHotMiddleware(webpackCompiler, {
path: `/eHot/${route.id}`
path: `/eHot`
});
route.hotMiddleware = hotMiddleware;
app.locals.hotMiddleware = hotMiddleware;
}
return route.hotMiddleware(request, response, () => {
return app.locals.hotMiddleware(request, response, () => {
next();
});
});
Expand Down
13 changes: 9 additions & 4 deletions packages/evershop/src/bin/lib/buildEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,17 @@ export async function buildEntry(routes, clientOnly = false) {
const url = route.isAdmin
? pathToFileURL(widget.settingComponent).toString()
: pathToFileURL(widget.component).toString();
imports.push(`import ${widget.type} from '${url}';`);
areas['*'][widget.type] = {
id: widget.type,
const id = generateComponentKey(
route.isAdmin
? `admin_widget_${widget.type}`
: `widget_${widget.type}`
);
imports.push(`import ${id} from '${url}';`);
areas['*'][id] = {
id,
sortOrder: widget.sortOrder || 0,
component: {
default: `---${widget.type}---`
default: `---${id}---`
}
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ export function findRoute(request) {
routes.find((r) => r.id === id) ||
routes.find((r) => r.id === 'notFound')
);
} else if (path.includes('/eHot/')) {
const id = path.split('/').pop();
return routes.find((r) => r.id === id);
} else if (path.includes('/eHot')) {
return routes.find((r) => r.id === 'homepage');
} else {
return routes.find((r) => r.id === 'notFound');
}
Expand Down
5 changes: 4 additions & 1 deletion packages/evershop/src/components/common/Area.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useAppState } from '@components/common/context/app.js';
import { generateComponentKey } from '@evershop/evershop/lib/webpack/util/keyGenerator.js';
import React from 'react';
import type { ElementType } from 'react';

Expand Down Expand Up @@ -56,7 +57,9 @@ function Area(props: AreaProps) {
const assignedWidgets: Component[] = [];

widgets.forEach((widget: Widget) => {
const w = wildCardWidgets[widget.type];
const adminKey = generateComponentKey(`admin_widget_${widget.type}`);
const frontKey = generateComponentKey(`widget_${widget.type}`);
const w = wildCardWidgets[adminKey] || wildCardWidgets[frontKey];
if (widget.areaId.includes(id) && w !== undefined) {
assignedWidgets.push({
id: widget.id,
Expand Down
11 changes: 8 additions & 3 deletions packages/evershop/src/components/common/react/server/Server.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import Area from '@components/common/Area.js';
import { Alert } from '@components/common/modal/Alert.js';
import React from 'react';
import { Route } from '../../../../types/route.js';

interface ServerHtmlProps {
route: Route;
css: string[];
js: string[];
appContext: string;
}
function ServerHtml({ css, js, appContext }: ServerHtmlProps) {
function ServerHtml({ route, css, js, appContext }: ServerHtmlProps) {
const classes = route.isAdmin
? `admin ${route.id}`
: `frontStore ${route.id}`;
return (
<>
<head>
Expand All @@ -18,8 +23,8 @@ function ServerHtml({ css, js, appContext }: ServerHtmlProps) {
))}
<Area noOuter id="head" />
</head>
<body id="body">
<div id="app" className="bg-background">
<body id="body" className={classes}>
<div id="app">
<Alert>
<Area id="body" className="wrapper" />
</Alert>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { resolve } from 'path';
import { getEnabledExtensions } from '../../bin/extension/index.js';
import { getCoreModules } from '../../bin/lib/loadModules.js';
import { CONSTANTS } from '../helpers.js';
import { getRoutes } from '../router/Router.js';
import { getEnabledTheme } from '../util/getEnabledTheme.js';
import { getEnabledWidgets } from '../widget/widgetManager.js';
import { scanRouteComponents } from './scanForComponents.js';
import { ComponentsMap, scanRouteComponents } from './scanForComponents.js';

export function getComponentsByRoute(route) {
const modules = [...getCoreModules(), ...getEnabledExtensions()];
Expand All @@ -29,3 +29,21 @@ export function getComponentsByRoute(route) {
);
}
}

interface AllRouteComponentsMap {
[routeId: string]: ComponentsMap;
}

/**
* Scan components for all routes
* @returns A map of route IDs to their components
*/
export function getAllRouteComponents(): AllRouteComponentsMap {
const allComponents: AllRouteComponentsMap = {};
const routes = getRoutes();
routes.forEach((route) => {
allComponents[route.id] = getComponentsByRoute(route);
});

return allComponents;
}
Loading