catalyst-core 0.0.1-beta.6 → 0.0.1-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -121
- package/changelog.md +3 -13
- package/dist/scripts/loadScriptsBeforeServerStarts.js +2 -2
- package/dist/server/renderer/document/Body.js +2 -5
- package/dist/server/renderer/document/Head.js +2 -2
- package/dist/server/renderer/extract.js +18 -12
- package/dist/server/renderer/handler.js +5 -6
- package/dist/webpack/babel-plugins/remove-ssr.plugin.js +1 -1
- package/dist/webpack/base.babel.js +2 -2
- package/dist/webpack/scssParams.js +2 -2
- package/package.json +8 -3
- package/dist/scripts/centralImport.js +0 -1
- package/dist/server/renderer/render.js +0 -21
package/README.md
CHANGED
|
@@ -1,146 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://onemg.gumlet.io/staging/7ee66dfb-b5fb-4fbe-8dea-789685e45f7a.svg">
|
|
4
|
+
<img alt="Catalyst logo" src="https://onemg.gumlet.io/staging/2fdb0975-8f51-4fd1-bd7d-6375d793f581.svg" height="128">
|
|
5
|
+
</picture>
|
|
6
|
+
</div>
|
|
4
7
|
|
|
5
8
|
## Table of Contents
|
|
6
9
|
|
|
7
10
|
- Overview
|
|
8
11
|
- Installation
|
|
9
|
-
|
|
10
|
-
- serverFetcher
|
|
11
|
-
- clientFetcher
|
|
12
|
-
- refetch (for data revalidation)
|
|
13
|
-
- State Management
|
|
14
|
-
|
|
12
|
+
|
|
15
13
|
## Overview
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
Catalyst offers a comprehensive suite of features designed for modern web development. It includes isomorphic rendering for optimal performance, an extendable server with full-stack capabilities, and configurable state management. The framework employs smart prefetching of data and chunks, allows easy configuration of global styles and layouts, and provides SEO optimization at both global and page levels.
|
|
19
16
|
## Installation
|
|
20
17
|
|
|
21
18
|
**System Requirements**
|
|
22
19
|
|
|
23
20
|
- Node version 20.4.0 or later
|
|
24
|
-
- macOS and Linux
|
|
21
|
+
- Compatible with **macOS** and **Linux**
|
|
25
22
|
|
|
26
23
|
**Automatic Installation**
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
Run the following commands in the directory where you want to set up the Catalyst app:
|
|
29
26
|
|
|
30
|
-
```
|
|
27
|
+
```bash
|
|
31
28
|
npx create-catalyst-app@latest
|
|
32
29
|
```
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- Enter the name of your Catalyst application.
|
|
37
|
-
- Choose state management.
|
|
38
|
-
- Once packages are installed,start the development server by running the following command.
|
|
39
|
-
|
|
40
|
-
```js
|
|
41
|
-
cd project-name && npm run start
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
- Navigate to http://localhost:3005
|
|
45
|
-
|
|
46
|
-
The dev server should be running now.
|
|
47
|
-
|
|
48
|
-
Visit our official documentation:
|
|
49
|
-
https://catalyst.1mg.com/public_docs/content/installation
|
|
50
|
-
|
|
51
|
-
## Data Fetching with Catalyst
|
|
52
|
-
|
|
53
|
-
we have serverFetcher function for fetching with SSR and clientFetcher function for fetching during client side rendering and navigations.
|
|
54
|
-
|
|
55
|
-
**serverFetcher**
|
|
56
|
-
|
|
57
|
-
server fetcher will get request, request params, search params and store (if project is setup with redux or rtk) as arguments. We can declare it as an async function and use await for fetching or use then chaining for data fetching.
|
|
58
|
-
|
|
59
|
-
if server fetcher is called for a route then client fetcher will not be called for that route, unless called with refetch.
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
Home.serverFetcher = async ({ req, params, searchParams }, { store }) => {
|
|
63
|
-
store.dispatch(someAction())
|
|
64
|
-
const res = await fetch("some_url")
|
|
65
|
-
const json = await res.json()
|
|
66
|
-
return json
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
data returned from fetcher function will be accessible through useCurrentRouteData() hook provided by router.
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
const [data, error, isFetched] = useCurrentRouteData()
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
error and loading state would be handled by router.
|
|
77
|
-
|
|
78
|
-
**clientFetcher**
|
|
79
|
-
|
|
80
|
-
client fetcher would be called on client side rendering and client side navigations. `store` would be available as a param in client side for dispatching redux/rtk actions.
|
|
81
|
-
|
|
82
|
-
```js
|
|
83
|
-
Home.clientFetcher = async ({ route, location, params, searchParams, navigate }, { store }) => {
|
|
84
|
-
store.dispatch(someAction())
|
|
85
|
-
const res = await fetch("some_url")
|
|
86
|
-
const json = await res.json()
|
|
87
|
-
return json
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
data returned from client fetcher function will be accessible through useCurrentRouteData() hook provided by router (hook for data access through client is same).
|
|
92
|
-
|
|
93
|
-
```js
|
|
94
|
-
const [data, error, isFetched] = useCurrentRouteData()
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**refetch (for data revalidation)**
|
|
98
|
-
|
|
99
|
-
refetch function can be used were we need to execute clientFetcher based on some condition(such as for infinite scroll or some state change inside container or onClick.)
|
|
100
|
-
|
|
101
|
-
We can pass arguments in refetch function which would
|
|
102
|
-
|
|
103
|
-
```js
|
|
104
|
-
const [data,error,isFetched,refetch] = useCurrentRouteData()
|
|
105
|
-
|
|
106
|
-
useEffect(()=>{
|
|
107
|
-
refetch({refetchArgument:some_value})
|
|
108
|
-
},[arg])
|
|
109
|
-
|
|
110
|
-
clientFetcher = ({},{refetchArgument}) => {
|
|
111
|
-
|
|
112
|
-
const res = await api_call // refetchArg can be used as a param in api call
|
|
113
|
-
return res
|
|
114
|
-
}
|
|
31
|
+
You will see some prompts to configure your application.
|
|
115
32
|
|
|
33
|
+
```bash
|
|
34
|
+
cd <name-of-your-project> && npm run start
|
|
116
35
|
```
|
|
117
36
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
state management wrappers are defined in stateProvider.js file
|
|
121
|
-
|
|
122
|
-
store can be configured by manipulating store/index.js as per user requirements (custom middlewares etc can be added in this way.
|
|
123
|
-
|
|
124
|
-
initial state and request object would be provided in createStore function which will be called on server and client, we use the params to add additional arguments and middlewares in redux store.
|
|
125
|
-
|
|
126
|
-
```js
|
|
127
|
-
const configureStore = (initialState, cookies, requestObj, customHeaders) => {
|
|
128
|
-
const api = fetchInstance
|
|
129
|
-
const store = createStore({
|
|
130
|
-
reducer: rootReducer,
|
|
131
|
-
middleware: (getDefaultMiddleware) =>
|
|
132
|
-
getDefaultMiddleware({
|
|
133
|
-
thunk: {
|
|
134
|
-
extraArgument: { api },
|
|
135
|
-
},
|
|
136
|
-
}),
|
|
137
|
-
preloadedState: initialState,
|
|
138
|
-
})
|
|
139
|
-
return store
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export default configureStore
|
|
143
|
-
```
|
|
37
|
+
The development server will start at ```http://localhost:3005```
|
|
144
38
|
|
|
145
39
|
## Documentation
|
|
146
40
|
|
package/changelog.md
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.0.1-beta.
|
|
3
|
+
## [0.0.1-beta.8] - 09-12-2024
|
|
4
4
|
|
|
5
5
|
### Changes
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- Module aliases defined for catalyst
|
|
10
|
-
- Added exports inside package.json for tree shakeable support for logger, caching and ClientRouter.js
|
|
11
|
-
- Hidden unnecessary files from published package:
|
|
12
|
-
.prettierrc.json
|
|
13
|
-
.eslintrc
|
|
14
|
-
.eslintignore
|
|
15
|
-
/.husky
|
|
16
|
-
/.github
|
|
17
|
-
commitlint.config.js
|
|
18
|
-
tsconfig.json
|
|
7
|
+
- Filter out host machine's environment variable from client environment variables
|
|
8
|
+
- Update @tata1mg/router's version to 0.0.1-beta.5.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var _registerAliases2=_interopRequireDefault(require("./registerAliases.js"));var _cssModulesRequireHook=_interopRequireDefault(require("@dr.pogodin/css-modules-require-hook"));var _path=_interopRequireDefault(require("path"));var _loadEnvironmentVariables=_interopRequireDefault(require("./loadEnvironmentVariables"));var _logger=require("@catalyst/logger.js");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}/* eslint-disable */const{cssModulesIdentifierDev}=require("@catalyst/root/config.json");// stores your config keys in enviorments variables
|
|
1
|
+
"use strict";var _registerAliases2=_interopRequireDefault(require("./registerAliases.js"));var _cssModulesRequireHook=_interopRequireDefault(require("@dr.pogodin/css-modules-require-hook"));var _path=_interopRequireDefault(require("path"));var _loadEnvironmentVariables=_interopRequireDefault(require("./loadEnvironmentVariables"));var _postcssScss=_interopRequireDefault(require("postcss-scss"));var _logger=require("@catalyst/logger.js");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}/* eslint-disable */const{cssModulesIdentifierDev}=require("@catalyst/root/config.json");// stores your config keys in enviorments variables
|
|
2
2
|
(0,_loadEnvironmentVariables.default)();// creates logger instance with provided config and stores them at global level.
|
|
3
3
|
(0,_logger.configureLogger)({enableDebugLogs:process.env.ENABLE_DEBUG_LOGS,enableFileLogging:process.env.ENABLE_FILE_LOGGING,enableConsoleLogging:process.env.ENABLE_CONSOLE_LOGGING});// compile css-variables in realtime in dev mode.
|
|
4
|
-
if(process.env.NODE_ENV==="development")(0,_cssModulesRequireHook.default)({extensions:[".scss",".css"],generateScopedName:cssModulesIdentifierDev,devMode:true,ignore:_path.default.join(process.env.src_path,"/src/static/css/base/(?!.*.scss$).*")});
|
|
4
|
+
if(process.env.NODE_ENV==="development")(0,_cssModulesRequireHook.default)({extensions:[".scss",".css"],processorOpts:{parser:_postcssScss.default.parse},generateScopedName:cssModulesIdentifierDev,devMode:true,ignore:_path.default.join(process.env.src_path,"/src/static/css/base/(?!.*.scss$).*")});
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.Body=Body;var _react=_interopRequireDefault(require("react"));var _propTypes=_interopRequireDefault(require("prop-types"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}/**
|
|
2
2
|
* Body component which will be used in page component
|
|
3
3
|
* @param {object} jsx - page jsx code
|
|
4
|
-
* @param {object} statusCode - document request status code
|
|
5
4
|
* @param {object} initialState - initial state object for redux store
|
|
6
5
|
* @param {object} firstFoldCss - style elements extracted for initial page load
|
|
7
|
-
* @param {object} firstFoldJS - javascript elements extracted for initial page load
|
|
8
6
|
* @param {object} fetcherData - contains data from executing serverFetcher function
|
|
9
7
|
* @param {object} children - contains any child elements defined within the component
|
|
10
|
-
*/function Body(props){const{jsx="",
|
|
8
|
+
*/function Body(props){const{jsx="",initialState={},fetcherData={},children}=props;return/*#__PURE__*/_react.default.createElement("body",null,jsx,/*#__PURE__*/_react.default.createElement("script",{/* eslint-disable */dangerouslySetInnerHTML:{__html:`
|
|
11
9
|
window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}
|
|
12
|
-
window.__STATUS_CODE__ = ${statusCode}
|
|
13
10
|
window.__ROUTER_INITIAL_DATA__ = ${JSON.stringify(fetcherData)}
|
|
14
|
-
`}}),children);}Body.propTypes={initialState:_propTypes.default.object,
|
|
11
|
+
`}}),children);}Body.propTypes={initialState:_propTypes.default.object,jsx:_propTypes.default.any,fetcherData:_propTypes.default.object,children:_propTypes.default.node};
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Head component which will be used in page rendering
|
|
3
3
|
* @param {boolean} isBot - checks if request is made by bot
|
|
4
4
|
* @param {string} pageCss - includes all styles for page css
|
|
5
|
-
* @param {object}
|
|
5
|
+
* @param {object} preloadJSLinks - async scripts for loading chunks
|
|
6
6
|
* @param {array} metaTags - user defined function which returns meta tags in array
|
|
7
7
|
* @param {string} publicAssetPath - public asset path for assets
|
|
8
8
|
* @param {object} children - contains any child elements defined within the component
|
|
9
|
-
*/function Head(props){const{pageCss,
|
|
9
|
+
*/function Head(props){const{pageCss,preloadJSLinks,metaTags,isBot,publicAssetPath,children}=props;if(children){return/*#__PURE__*/_react.default.createElement("head",null,children,metaTags&&metaTags,!isBot&&pageCss&&/*#__PURE__*/_react.default.createElement("style",{dangerouslySetInnerHTML:{__html:pageCss}}),!isBot&&preloadJSLinks);}return/*#__PURE__*/_react.default.createElement("head",null,/*#__PURE__*/_react.default.createElement("meta",{charSet:"utf-8"}),/*#__PURE__*/_react.default.createElement("meta",{name:"viewport",content:"width=device-width, initial-scale=1"}),publicAssetPath&&/*#__PURE__*/_react.default.createElement("link",{rel:"preconnect",href:publicAssetPath}),publicAssetPath&&/*#__PURE__*/_react.default.createElement("link",{rel:"dns-prefetch",href:publicAssetPath}),metaTags&&metaTags,!isBot&&pageCss&&/*#__PURE__*/_react.default.createElement("style",{dangerouslySetInnerHTML:{__html:pageCss}}),!isBot&&preloadJSLinks);}Head.propTypes={isBot:_propTypes.default.bool,preloadJSLinks:_propTypes.default.object,pageCss:_propTypes.default.string,metaTags:_propTypes.default.array,publicAssetPath:_propTypes.default.string,children:_propTypes.default.node};
|
|
@@ -1,21 +1,27 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.cacheCSS=cacheCSS;exports.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.cacheAndFetchAssets=void 0;exports.cacheCSS=cacheCSS;exports.cachePreloadJSLinks=cachePreloadJSLinks;exports.default=_default;var _path=_interopRequireDefault(require("path"));var _fs=_interopRequireDefault(require("fs"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}function cachePreloadJSLinks(key,data){if(!process.preloadJSLinkCache){process.preloadJSLinkCache={};}let preloadJSLinks=[];if(Array.isArray(data)){try{preloadJSLinks=data.filter(asset=>asset?.props?.as==="script");}catch(error){}}process.preloadJSLinkCache[key]=preloadJSLinks;}/**
|
|
2
2
|
* Stores css chunks styles into cache in string format
|
|
3
3
|
* @param {string} key - router path
|
|
4
4
|
* @param {object} data - css elements array extracted through loadable chunk extracter
|
|
5
|
-
*/function cacheCSS(key,data){if(!process.cssCache){process.cssCache={};}let pageCss="";if(Array.isArray(data)){try{data.map(assetChunk=>{const assetPathArr=assetChunk.key.split("/");const assetName=assetPathArr[assetPathArr.length-1];const ext=_path.default.extname(assetName);if(ext===".css")
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
*/function cacheCSS(key,data){if(!process.cssCache){process.cssCache={};}let pageCss="";let listOfCachedAssets={};if(Array.isArray(data)){try{if(process.env.NODE_ENV==="production"){data.map(assetChunk=>{const assetPathArr=assetChunk.key.split("/");const assetName=assetPathArr[assetPathArr.length-1];const ext=_path.default.extname(assetName);if(ext===".css"){// if css file has not already been cached, add the content of this CSS file in pageCSS
|
|
6
|
+
if(!listOfCachedAssets[assetName]&&!process.cssCache?.[key]?.listOfCachedAssets?.[assetName]){pageCss+=_fs.default.readFileSync(_path.default.resolve(process.env.src_path,`${process.env.BUILD_OUTPUT_PATH}/public`,assetName));listOfCachedAssets[assetName]=true;}}});}}catch(error){}}// if css cache exists for a route and there are some uncached css, add that css to the cache
|
|
7
|
+
// this will run on subsequent hits and will add css of uncached widgets to the cache
|
|
8
|
+
if(process.cssCache[key]){if(pageCss!==""){let existingListOfCachedAssets=process.cssCache[key].listOfCachedAssets;const newPageCSS=process.cssCache[key].pageCss+pageCss;let newListOfCachedAssets={...existingListOfCachedAssets,...listOfCachedAssets};process.cssCache[key]={pageCss:newPageCSS,listOfCachedAssets:newListOfCachedAssets};}}else{// create css cache for a page. This will run on the first hit.
|
|
9
|
+
process.cssCache[key]={pageCss,listOfCachedAssets};}return pageCss;}/**
|
|
10
10
|
* returns cached css
|
|
11
11
|
* @param {string} key - router path
|
|
12
12
|
* @return {string} - cached css
|
|
13
|
-
*/function fetchCachedCSS(key){return process.cssCache&&process.cssCache[key]?process.cssCache[key]:null;}/**
|
|
14
|
-
* returns cached js
|
|
15
|
-
* @param {string} key - router path
|
|
16
|
-
* @return {string} - cached js
|
|
17
|
-
*/function fetchCachedJS(key){return process.jsCache&&process.jsCache[key]?process.jsCache[key]:null;}/**
|
|
13
|
+
*/function fetchCachedCSS(key){return process.cssCache&&process.cssCache[key]?process.cssCache[key].pageCss:"";}function fetchPreloadJSLinkCache(key){return process.preloadJSLinkCache&&process.preloadJSLinkCache[key]?process.preloadJSLinkCache[key]:null;}/**
|
|
18
14
|
* stores css and js in cache
|
|
19
15
|
* @param {object} res - response object
|
|
20
16
|
* @param {string} route - route path
|
|
21
|
-
*/function _default(res,route){try{const requestPath=route.path;const cachedCss=fetchCachedCSS(requestPath);const
|
|
17
|
+
*/function _default(res,route){try{const requestPath=route.path;const cachedCss=fetchCachedCSS(requestPath);const cachedPreloadJSLinks=fetchPreloadJSLinkCache(requestPath);if(cachedCss||cachedPreloadJSLinks){res.locals.pageCss=cachedCss;res.locals.preloadJSLinks=cachedPreloadJSLinks;return;}}catch(error){}}const cacheAndFetchAssets=({webExtractor,res,isBot})=>{// For bot first fold css and js would become complete page css and js
|
|
18
|
+
let firstFoldCss="";let firstFoldJS="";const isProd=process.env.NODE_ENV==="production";const{routePath,preloadJSLinks}=res.locals;const linkElements=webExtractor.getLinkElements();// We want to cache/or check for update css on every call
|
|
19
|
+
// We want to extract script tags for every call that will get added to body.
|
|
20
|
+
// Their corresponding preloaded link script tags are already present in head.
|
|
21
|
+
if(routePath){if(!isBot){if(isProd){firstFoldCss=cacheCSS(routePath,linkElements);firstFoldCss=`<style>${firstFoldCss}</style>`;}else{cacheCSS(routePath,linkElements);firstFoldCss=webExtractor.getStyleTags();}}// firstFoldJS = webExtractor.getScriptTags({ nonce: cspNonce })
|
|
22
|
+
firstFoldJS=webExtractor.getScriptTags();}// This block will run for the first time and cache preloaded JS Links for second render
|
|
23
|
+
// firstFoldJS ->scripts gets inject in body
|
|
24
|
+
// firstFoldCss -> Inline css gets injected in body only for the first render
|
|
25
|
+
if(!isProd||isBot||routePath&&!preloadJSLinks){// For production, we inject link tags with preload/prefetch using getLinkElements and inlining them via file reads
|
|
26
|
+
// For local, given we have assets in memory we dont read from file rather directly inject via link elements returned without preload/prefetch
|
|
27
|
+
!isBot&&cachePreloadJSLinks(routePath,linkElements);}return{firstFoldCss,firstFoldJS};};exports.cacheAndFetchAssets=cacheAndFetchAssets;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=_default;var _fs=_interopRequireDefault(require("fs"));var _path=_interopRequireDefault(require("path"));var _react=_interopRequireDefault(require("react"));var
|
|
2
|
-
const getMatchRoutes=(routes,req,res,store,context,fetcherData,basePath="",webExtractor)=>{return routes.reduce((matches,route)=>{const{path}=route;const match=(0,_router.matchPath)({path:`${basePath}/${path}`,caseSensitive:false,end:true},req.baseUrl||"/");if(match){if(
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=_default;var _fs=_interopRequireDefault(require("fs"));var _path=_interopRequireDefault(require("path"));var _react=_interopRequireDefault(require("react"));var _extract=_interopRequireWildcard(require("./extract"));var _reactRedux=require("react-redux");var _document=require("./document");var _server=require("react-router-dom/server");var _ServerRouter=_interopRequireDefault(require("@catalyst/router/ServerRouter.js"));var _index=_interopRequireDefault(require("@catalyst/template/src/js/containers/App/index.js"));var _server2=require("@loadable/server");var _server3=require("react-dom/server");var _userAgentUtil=require("@catalyst/server/utils/userAgentUtil");var _router=require("@tata1mg/router");var _validator=require("@catalyst/server/utils/validator");var _document2=_interopRequireDefault(require("@catalyst/template/server/document.js"));var _utils=require("@catalyst/template/src/js/routes/utils.js");function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var r=new WeakMap(),t=new WeakMap();return(_getRequireWildcardCache=function(e){return e?t:r;})(e);}function _interopRequireWildcard(e,r){if(!r&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var t=_getRequireWildcardCache(r);if(t&&t.has(e))return t.get(e);var n={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in e)if("default"!==u&&Object.prototype.hasOwnProperty.call(e,u)){var i=a?Object.getOwnPropertyDescriptor(e,u):null;i&&(i.get||i.set)?Object.defineProperty(n,u,i):n[u]=e[u];}return n.default=e,t&&t.set(e,n),n;}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}const storePath=_path.default.resolve(`${process.env.src_path}/src/js/store/index.js`);let createStore;if(_fs.default.existsSync(storePath)){try{const{default:configureStore}=require(`${process.env.src_path}/src/js/store/index.js`);createStore=configureStore;}catch(error){createStore=()=>{return{getState:()=>{}};};}}else{createStore=()=>{return{getState:()=>{}};};}const isProduction=process.env.NODE_ENV==="production";// matches request route with routes defined in the application.
|
|
2
|
+
const getMatchRoutes=(routes,req,res,store,context,fetcherData,basePath="",webExtractor)=>{return routes.reduce((matches,route)=>{const{path}=route;const match=(0,_router.matchPath)({path:`${basePath}/${path}`,caseSensitive:false,end:true},req.baseUrl||"/");if(match){if(!res.locals.pageCss&&!res.locals.preloadJSLinks&&!res.locals.routePath){res.locals.routePath=path;(0,_extract.default)(res,route);}if(!res.locals.pageCss&&!res.locals.preloadJSLinks){//moving routing logic outside of the App and using ServerRoutes for creating routes on server instead
|
|
3
3
|
(0,_server3.renderToString)(/*#__PURE__*/_react.default.createElement(_server2.ChunkExtractorManager,{extractor:webExtractor},/*#__PURE__*/_react.default.createElement(_reactRedux.Provider,{store:store},/*#__PURE__*/_react.default.createElement(_server.StaticRouter,{context:context,location:req.originalUrl},/*#__PURE__*/_react.default.createElement(_ServerRouter.default,{store:store,intialData:fetcherData})))));}const wc=route.component;matches.push({route,match,serverSideFunction:wc&&wc.serverSideFunction||(()=>Promise.resolve())});}if(!match&&route.children){// recursively try to match nested routes
|
|
4
4
|
const nested=getMatchRoutes(route.children,req,res,store,context,fetcherData,`${basePath}/${path}`,webExtractor);if(nested.length){matches=matches.concat(nested);}}return matches;},[]);};// Preloads chunks required for rendering document
|
|
5
5
|
const getComponent=(store,context,req,fetcherData)=>{return/*#__PURE__*/_react.default.createElement("div",{id:"app"},/*#__PURE__*/_react.default.createElement(_reactRedux.Provider,{store:store},/*#__PURE__*/_react.default.createElement(_server.StaticRouter,{context:context,location:req.originalUrl},/*#__PURE__*/_react.default.createElement(_ServerRouter.default,{store:store,intialData:fetcherData}))));};// sends document after rendering
|
|
6
|
-
const renderMarkUp=async(errorCode,req,res,metaTags,fetcherData,store,matches,context,webExtractor)=>{const deviceDetails=(0,_userAgentUtil.getUserAgentDetails)(req.headers["user-agent"]||"");const isBot=deviceDetails.googleBot?true:false
|
|
7
|
-
const
|
|
8
|
-
const shellEnd=_render.default.renderEnd(webExtractor,state,res,jsx,errorCode,fetcherData);const finalProps={...shellStart,...shellEnd,jsx:jsx,req,res};let CompleteDocument=()=>{if((0,_validator.validateCustomDocument)(_document2.default)){return(0,_document2.default)(finalProps);}else{return/*#__PURE__*/_react.default.createElement("html",{lang:finalProps.lang},/*#__PURE__*/_react.default.createElement(_document.Head,{isBot:finalProps.isBot,pageJS:finalProps.pageJS,pageCss:finalProps.pageCss,fetcherData:finalProps.fetcherData,metaTags:finalProps.metaTags,publicAssetPath:finalProps.publicAssetPath}),/*#__PURE__*/_react.default.createElement(_document.Body,{initialState:finalProps.initialState,firstFoldCss:finalProps.firstFoldCss,firstFoldJS:finalProps.firstFoldJS,jsx:finalProps.jsx,statusCode:finalProps.statusCode,fetcherData:finalProps.fetcherData}));}};try{let status=matches.length&&matches[0].match.path==="*"?404:200;res.set({"content-type":"text/html; charset=utf-8"});res.status(status);const{pipe}=(0,_server3.renderToPipeableStream)(/*#__PURE__*/_react.default.createElement(CompleteDocument,null),{onShellReady(){res.setHeader("content-type","text/html");pipe(res);res.end();},onError(error){logger.error({message:`\n Error while renderToPipeableStream : ${error.toString()}`});}});}catch(error){logger.error("Error in rendering document on server:"+error);}};/**
|
|
6
|
+
const renderMarkUp=async(errorCode,req,res,metaTags,fetcherData,store,matches,context,webExtractor)=>{const deviceDetails=(0,_userAgentUtil.getUserAgentDetails)(req.headers["user-agent"]||"");const isBot=deviceDetails.googleBot?true:false;let state=store.getState();const jsx=webExtractor.collectChunks(getComponent(store,context,req,fetcherData));const{IS_DEV_COMMAND,WEBPACK_DEV_SERVER_HOSTNAME,WEBPACK_DEV_SERVER_PORT}=process.env;let publicAssetPath=`${process.env.PUBLIC_STATIC_ASSET_URL}${process.env.PUBLIC_STATIC_ASSET_PATH}`;// serves assets from localhost on running devBuild and devServe command
|
|
7
|
+
if(IS_DEV_COMMAND==="true"){publicAssetPath=`http://${WEBPACK_DEV_SERVER_HOSTNAME}:${WEBPACK_DEV_SERVER_PORT}/assets/`;}const finalProps={req,res,lang:"en",pageCss:res.locals.pageCss,preloadJSLinks:res.locals.preloadJSLinks,metaTags,isBot,publicAssetPath,jsx,initialState:state,fetcherData};let CompleteDocument=()=>{if((0,_validator.validateCustomDocument)(_document2.default)){return(0,_document2.default)(finalProps);}else{return/*#__PURE__*/_react.default.createElement("html",{lang:finalProps.lang},/*#__PURE__*/_react.default.createElement(_document.Head,{isBot:finalProps.isBot,pageCss:finalProps.pageCss,metaTags:finalProps.metaTags,preloadJSLinks:finalProps.preloadJSLinks,publicAssetPath:finalProps.publicAssetPath}),/*#__PURE__*/_react.default.createElement(_document.Body,{jsx:finalProps.jsx,fetcherData:finalProps.fetcherData,initialState:finalProps.initialState}));}};try{let status=matches.length&&matches[0].match.path==="*"?404:200;res.set({"content-type":"text/html; charset=utf-8"});res.status(status);const{pipe}=(0,_server3.renderToPipeableStream)(/*#__PURE__*/_react.default.createElement(CompleteDocument,null),{onShellReady(){res.setHeader("content-type","text/html");pipe(res);},onAllReady(){const{firstFoldCss,firstFoldJS}=(0,_extract.cacheAndFetchAssets)({webExtractor,res,isBot});res.write(firstFoldCss);res.write(firstFoldJS);res.end();},onError(error){logger.error({message:`\n Error while renderToPipeableStream : ${error.toString()}`});}});}catch(error){logger.error("Error in rendering document on server:"+error);}};/**
|
|
9
8
|
* middleware for document handling
|
|
10
9
|
* @param {object} req - request object
|
|
11
10
|
* @param {object} res - response object
|
|
12
11
|
*/async function _default(req,res){try{let context={};let fetcherData={};let webStats=_path.default.join(__dirname,"../../..",`loadable-stats.json`);if(isProduction){webStats=_path.default.join(process.env.src_path,`${process.env.BUILD_OUTPUT_PATH}/public/loadable-stats.json`);}const webExtractor=new _server2.ChunkExtractor({statsFile:webStats,entrypoints:["app"]});// creates store
|
|
13
|
-
const store=(0,_validator.validateConfigureStore)(createStore)?createStore({},req):null;// user defined routes
|
|
12
|
+
const store=(0,_validator.validateConfigureStore)(createStore)?createStore({},req,res):null;// user defined routes
|
|
14
13
|
const routes=(0,_validator.validateGetRoutes)(_utils.getRoutes)?(0,_utils.getRoutes)():[];// Matches req url with routes
|
|
15
14
|
const matches=getMatchRoutes(routes,req,res,store,context,fetcherData,undefined,webExtractor);const allMatches=(0,_router.matchRoutes)((0,_utils.getRoutes)(),req.baseUrl);let allTags=[];// Executing app server side function
|
|
16
15
|
_index.default.serverSideFunction({store,req,res})// Executing serverFetcher functions with serverDataFetcher provided by router and returning document
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* @description babel plugin used to remove unwanted code from the build.
|
|
3
3
|
* @return babel plugin object
|
|
4
4
|
*/function _default(){return{name:"ast-transform",// not required
|
|
5
|
-
visitor:{ImportDefaultSpecifier(path){path.parentPath.parent.body=path.parentPath.parent.body.filter(val=>val?.expression?.left?.property?.name!=="serverSideFunction");}}};}
|
|
5
|
+
visitor:{ImportDefaultSpecifier(path){path.parentPath.parent.body=path.parentPath.parent.body.filter(val=>val?.expression?.left?.property?.name!=="serverSideFunction"&&val?.expression?.left?.property?.name!=="serverFetcher");}}};}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=exports.basePlugins=void 0;var _path=_interopRequireDefault(require("path"));var _webpack=_interopRequireDefault(require("webpack"));var _webpackPlugin=_interopRequireDefault(require("@loadable/webpack-plugin"));var _miniCssExtractPlugin=_interopRequireDefault(require("mini-css-extract-plugin"));var _webpackBundleAnalyzer=require("webpack-bundle-analyzer");var _config=_interopRequireDefault(require("@catalyst/root/config.json"));var _package=require("@catalyst/template/package.json");var _scssParams=require("@catalyst/webpack/scssParams");var _babelConfig=_interopRequireDefault(require("@catalyst/webpack/babel.config.ssr"));var _babelConfig2=_interopRequireDefault(require("@catalyst/webpack/babel.config.client"));var _loadEnvironmentVariables=_interopRequireDefault(require("@catalyst/scripts/loadEnvironmentVariables"));var _config2=require("@catalyst/template/config/config.json");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}(0,_loadEnvironmentVariables.default)();const isDev=process.env.NODE_ENV==="development";const isSSR=!!process.env.SSR||false;const basePlugins=exports.basePlugins=[new _webpackPlugin.default({filename:"loadable-stats.json",writeToDisk:{filename:_path.default.join(__dirname,"../..")}}),// **This loads process.env variable during webpack build process
|
|
2
|
-
new _webpack.default.DefinePlugin({"process.env":([..._config2.CLIENT_ENV_VARIABLES
|
|
2
|
+
new _webpack.default.DefinePlugin({"process.env":([..._config2.CLIENT_ENV_VARIABLES,"BUILD_OUTPUT_PATH","PUBLIC_STATIC_ASSET_PATH","PUBLIC_STATIC_ASSET_URL","src_path","PWD"]||[]).reduce((clientEnvMap,env)=>{clientEnvMap[env]=JSON.stringify(process.env[env]);return clientEnvMap;},{})}),// ** This is used to analyze bundle size.
|
|
3
3
|
_config2.ANALYZE_BUNDLE&&new _webpackBundleAnalyzer.BundleAnalyzerPlugin({generateStatsFile:_config2.ANALYZE_BUNDLE}),new _webpack.default.IgnorePlugin({resourceRegExp:/^\.\/locale$/,contextRegExp:/moment$/})];const{IS_DEV_COMMAND,PUBLIC_STATIC_ASSET_URL,PUBLIC_STATIC_ASSET_PATH,WEBPACK_DEV_SERVER_HOSTNAME,WEBPACK_DEV_SERVER_PORT,NODE_SERVER_HOSTNAME,NODE_SERVER_PORT}=process.env;let publicPath=isDev?`http://${WEBPACK_DEV_SERVER_HOSTNAME}:${WEBPACK_DEV_SERVER_PORT}/`:`${PUBLIC_STATIC_ASSET_URL}${PUBLIC_STATIC_ASSET_PATH}`;// serves assets from local on running devBuild and devServe command
|
|
4
|
-
if(
|
|
4
|
+
if(IS_DEV_COMMAND==="true"&&!isDev){publicPath=`http://${NODE_SERVER_HOSTNAME}:${NODE_SERVER_PORT}/assets/`;}var _default=exports.default={context:_path.default.resolve(process.env.src_path),mode:isDev?"development":"production",entry:{app:[_path.default.resolve(process.env.src_path,"./client/index.js")]},output:{path:_path.default.join(process.env.src_path,`${process.env.BUILD_OUTPUT_PATH}/public`),filename:process.env.NODE_ENV==="development"?"[name].bundle.js":"[name].[contenthash].js",chunkFilename:process.env.NODE_ENV==="development"?"[name].bundle.js":"[name].[contenthash].js",publicPath:publicPath},resolve:{fallback:{url:require.resolve("url")},extensions:[".js",".jsx",".scss"],alias:Object.keys(_package._moduleAliases||{}).reduce((moduleEnvMap,alias)=>{moduleEnvMap[alias]=_path.default.join(process.env.src_path,..._package._moduleAliases[alias].split("/"));return moduleEnvMap;},{})},plugins:basePlugins,module:{rules:[{test:/\.jsx$|\.js$/,exclude:_path.default.resolve(process.env.src_path,"./node_modules"),use:{loader:"babel-loader",options:isSSR?_babelConfig.default:_babelConfig2.default}},{// This loader processes all the .scss files that should be modularized. This should exclude anything inside node_modules and everything inside src/css/base since they should be globally scoped.
|
|
5
5
|
test:/\.scss$/,exclude:[_path.default.resolve(process.env.src_path,"./node_modules"),_path.default.resolve(process.env.src_path,"./src/static/css/base")],use:[isDev&&"css-hot-loader",!isSSR&&_miniCssExtractPlugin.default.loader,{loader:"css-loader",options:{modules:{mode:"local",exportOnlyLocals:!isDev&&isSSR,localIdentName:isDev?_config.default.cssModulesIdentifierDev:_config.default.cssModulesIdentifierProd}}},{loader:"postcss-loader"},{loader:"sass-loader",options:{additionalData:"$font_url: "+(0,_scssParams.fontUrl)()+";"+"$url_for: "+(0,_scssParams.imageUrl)()+";"}},{loader:"sass-resources-loader",options:{resources:[_path.default.resolve(process.env.src_path,"./src/static/css/resources/*.scss")]}}]},{// In development mode, client request app.css ,which has all the css in node_modules and src/static/css/base, This is served by webpack-dev-server. However in prod this css is injected in the doc sent from the server and needs to be global, so we don't pass the files through css-loader to be modularized.
|
|
6
6
|
test:/\.scss$/,include:[_path.default.resolve(process.env.src_path,"./node_modules"),_path.default.resolve(process.env.src_path,"./src/static/css/base")],use:[isDev&&"css-hot-loader",!isSSR&&_miniCssExtractPlugin.default.loader,{loader:"css-loader"},{loader:"postcss-loader"},{loader:"sass-loader",options:{additionalData:"$font_url: "+(0,_scssParams.fontUrl)()+";"+"$url_for: "+(0,_scssParams.imageUrl)()+";"}},{loader:"sass-resources-loader",options:{resources:[_path.default.resolve(process.env.src_path,"./src/static/css/resources/*.scss")]}}]},{test:/\.css$/,use:[!isSSR&&_miniCssExtractPlugin.default.loader,"css-loader","postcss-loader"]},{test:/\.(png|jpg|gif|jpeg|ico?)$/,use:["url-loader?limit=10240","img-loader"]},{test:/\.svg$/i,issuer:/\.[jt]sx?$/,use:["@svgr/webpack","url-loader?limit=10240","img-loader"]},{// This loader loads fonts in src/static/fonts using file-loader
|
|
7
7
|
test:/\.(ttf|eot|woff2|json?)$/,use:[{loader:"url-loader",options:{limit:10240,outputPath:[_path.default.resolve(process.env.src_path,"./src/static/fonts/")]}},"file-loader"]},{// This loader loads html files
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @description generate assets url according to enviorment
|
|
3
3
|
* @returns returns path required for loading assets according to enviorment
|
|
4
4
|
*/const imageUrl=()=>{const{PUBLIC_STATIC_ASSET_URL,PUBLIC_STATIC_ASSET_PATH,IS_DEV_COMMAND,NODE_SERVER_HOSTNAME,NODE_SERVER_PORT}=process.env;let publicPath=`${PUBLIC_STATIC_ASSET_URL}${PUBLIC_STATIC_ASSET_PATH}`;// serves assets from localhost on running devBuild and devServe command
|
|
5
|
-
if(
|
|
5
|
+
if(IS_DEV_COMMAND==="true"){publicPath=`http://${NODE_SERVER_HOSTNAME}:${NODE_SERVER_PORT}/${PUBLIC_STATIC_ASSET_PATH}`;}const imagePath=JSON.stringify(`${publicPath}images/`);return imagePath;};/**
|
|
6
6
|
* @description generate assets font url according to enviorment
|
|
7
7
|
* @returns returns path required for loading fonts according to enviorment
|
|
8
8
|
*/exports.imageUrl=imageUrl;const fontUrl=()=>{const{PUBLIC_STATIC_ASSET_URL,PUBLIC_STATIC_ASSET_PATH,IS_DEV_COMMAND,NODE_SERVER_HOSTNAME,NODE_SERVER_PORT}=process.env;let publicPath=`${PUBLIC_STATIC_ASSET_URL}${PUBLIC_STATIC_ASSET_PATH}`;// serves assets from localhost on running devBuild and devServe command
|
|
9
|
-
if(
|
|
9
|
+
if(IS_DEV_COMMAND==="true"){publicPath=`http://${NODE_SERVER_HOSTNAME}:${NODE_SERVER_PORT}/${PUBLIC_STATIC_ASSET_PATH}`;}const fontPath=JSON.stringify(`${publicPath}fonts/`);return fontPath;};exports.fontUrl=fontUrl;
|
package/package.json
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "catalyst-core",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.8",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"description": "Web framework that provides great performance out of the box",
|
|
6
6
|
"bin": {
|
|
7
7
|
"catalyst": "bin/catalyst.js"
|
|
8
8
|
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/tata1mg/catalyst-core.git"
|
|
12
|
+
},
|
|
9
13
|
"_moduleAliases": {
|
|
10
14
|
"@catalyst/template": ".",
|
|
11
15
|
"@catalyst/template/src": "src",
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
"@loadable/webpack-plugin": "^5.15.2",
|
|
49
53
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
|
|
50
54
|
"@svgr/webpack": "^8.1.0",
|
|
51
|
-
"@tata1mg/router": "
|
|
55
|
+
"@tata1mg/router": "0.0.1-beta.5",
|
|
52
56
|
"app-root-path": "^3.1.0",
|
|
53
57
|
"babel-loader": "^9.1.3",
|
|
54
58
|
"babel-plugin-transform-react-remove-prop-types": "^0.4.24",
|
|
@@ -67,6 +71,7 @@
|
|
|
67
71
|
"module-alias": "^2.2.3",
|
|
68
72
|
"picocolors": "^1.0.0",
|
|
69
73
|
"postcss-loader": "^7.3.3",
|
|
74
|
+
"postcss-scss": "^4.0.9",
|
|
70
75
|
"react": "^18.2.0",
|
|
71
76
|
"react-dom": "^18.2.0",
|
|
72
77
|
"react-redux": "^8.1.3",
|
|
@@ -108,4 +113,4 @@
|
|
|
108
113
|
"prettier . --write"
|
|
109
114
|
]
|
|
110
115
|
}
|
|
111
|
-
}
|
|
116
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ROUTE_UTILS=void 0;const ROUTE_UTILS=exports.ROUTE_UTILS=`${process.env.src_path}/src/js/routes/utils.js`;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.default=void 0;var _extract=require("./extract");/**
|
|
2
|
-
* returns data which will be used in Head component for page rendering
|
|
3
|
-
* @param {string} pageCss - cached styles for page
|
|
4
|
-
* @param {string} pageJS - cached javscript elements for page
|
|
5
|
-
* @param {function} metaTagFunction - user defined function which returns meta tags in array
|
|
6
|
-
* @param {boolean} isBot - checks if request is made by bot
|
|
7
|
-
* @param {object} fetcherData - router fetched data
|
|
8
|
-
*/const renderStart=(pageCss,pageJS,metaTags,isBot,fetcherData)=>{const{IS_DEV_COMMAND,WEBPACK_DEV_SERVER_HOSTNAME,WEBPACK_DEV_SERVER_PORT}=process.env;let publicAssetPath=`${process.env.PUBLIC_STATIC_ASSET_URL}${process.env.PUBLIC_STATIC_ASSET_PATH}`;// serves assets from localhost on running devBuild and devServe command
|
|
9
|
-
if(JSON.parse(IS_DEV_COMMAND)){publicAssetPath=`http://${WEBPACK_DEV_SERVER_HOSTNAME}:${WEBPACK_DEV_SERVER_PORT}/assets/`;}return{pageCss,pageJS,metaTags,isBot,publicAssetPath,fetcherData};};/**
|
|
10
|
-
* returns data which will be used in body component for page rendering
|
|
11
|
-
* @param {object} webExtractor - loadable object which holds chunking function
|
|
12
|
-
* @param {string} initialState - reducer initial state
|
|
13
|
-
* @param {function} res - response object
|
|
14
|
-
* @param {boolean} jsx - jsx which needs to be render on server side
|
|
15
|
-
* @param {string|number|null} errorCode - error code
|
|
16
|
-
* @param {object} fetcherData - router fetched data
|
|
17
|
-
*/const renderEnd=(webExtractor,initialState={},res,jsx,errorCode,fetcherData)=>{// For bot first fold css and js would become complete page css and js
|
|
18
|
-
let firstFoldCss="";let firstFoldJS="";const isProd=process.env.NODE_ENV==="production";const{routePath,pageCss,pageJS}=res.locals;// Development: Extracts styles and javascript elements for injecting in Body Component.
|
|
19
|
-
// NOTE: Caching of styles and javascript is not enabled in development.
|
|
20
|
-
if(!isProd){firstFoldCss=webExtractor.getStyleElements();firstFoldJS=webExtractor.getScriptElements();}// Production: Extract styles and javscript elements if they are not found in cache and stores them in cache.
|
|
21
|
-
if(isProd&&routePath&&(!pageCss||!pageJS)){firstFoldCss=webExtractor.getStyleElements();firstFoldJS=webExtractor.getScriptElements();(0,_extract.cacheCSS)(routePath,webExtractor.getLinkElements());(0,_extract.cacheJS)(routePath,webExtractor.getScriptElements());}return{initialState,firstFoldCss,firstFoldJS,jsx,errorCode,fetcherData};};var _default=exports.default={renderStart,renderEnd};
|