Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Used styles check #22

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
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
795 changes: 474 additions & 321 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"terser-webpack-plugin": "^5.3.6",
"ts-jest": "^29.0.3",
"ts-loader": "^9.4.1",
"webpack": "^5.74.0",
"webpack": "^5.88.0",
"webpack-bundle-analyzer": "^4.6.1",
"webpack-cli": "^4.10.0",
"webpack-manifest-plugin": "^5.0.0",
Expand All @@ -77,7 +77,10 @@
"react-dom": "^18.2.0",
"react-router-dom": "^6.4.1",
"serialize-javascript": "^6.0.0",
"styled-components": "^5.3.6"
"styled-components": "^5.3.6",
"typescript": "^5.2.2",
"used-styles": "^2.5.2",
"webpack-imported": "^1.2.2"
},
"husky": {
"hooks": {
Expand Down
14 changes: 12 additions & 2 deletions src/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { cookieStore } from '@general-infrastructure/stores/cookieStore';
import {ACCESS_TOKEN, REFRESH_TOKEN} from '@general-infrastructure/constants/cookies';
import {AuthContext} from '@client/modules/authorization/context';

import s from './css.module.css';

const App: React.FC = () => {
const {isLoading, data} = useRefreshToken({
Expand All @@ -21,18 +22,23 @@ const App: React.FC = () => {
},
});

if(typeof window !== 'undefined') {
console.log('HYDRATION RENDER: ', [...document.querySelectorAll('*')]);
}

useEffect(() => {
const refreshToken = data?.data?.refreshToken;
if(refreshToken) {
cookieStore.set(REFRESH_TOKEN, refreshToken);
}
console.log('after render: ', [...document.querySelectorAll('*')]);
}, [data]);

const isAuthorized = useMemo(() => isLoading ? false : !!data?.data?.refreshToken, [isLoading, data]);

return (
// @TODO add error boundary
<Suspense fallback={'Loading...'}>
<>
<AuthContext.Provider value={{
isAuthorized,
isLoading,
Expand All @@ -46,12 +52,16 @@ const App: React.FC = () => {
<Link to="/lazy">lazy</Link>
<Link to="/super-private-page">SUPER PRIVATE DONT CLICK</Link>
<Link to="/microfronted/home">Microfrontend home</Link>
{new Array(100).fill(<div></div>).map((node, i) => <div key={i}></div>)}
{/* @TODO не могу найти кейс где бы линк был в руте пряымо, чтобы точно сказать
работает ли скрипт без ошибок гидрации или нет */}
<Routes />
{new Array(100).fill(<div></div>).map((node, i) => <div key={i}></div>)}
</div>
</Container>
</AppThemeProdvider>
</AuthContext.Provider>
</Suspense>
</>
);
};

Expand Down
41 changes: 29 additions & 12 deletions src/client/bootstrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,36 @@ import { QueryClient, QueryClientProvider, Hydrate } from '@tanstack/react-query
import './styles/index.scss';
import App from './App';

const container = document.getElementById('root') as HTMLElement;

// @TODO DECLARE WINDOW TYPE
const dehydratedState = (window as any).__REACT_QUERY_STATE__;
export const queryClient = new QueryClient();

hydrateRoot(
container,
<BrowserRouter>
<QueryClientProvider client={queryClient}>
<Hydrate state={dehydratedState}>
<App />
</Hydrate>
</QueryClientProvider>
</BrowserRouter>,
);
const hydrate = () => {
const container = document.getElementById('root') as HTMLElement;

hydrateRoot(
container,
<BrowserRouter>
<QueryClientProvider client={queryClient}>
<Hydrate state={dehydratedState}>
<App />
</Hydrate>
</QueryClientProvider>
</BrowserRouter>,
);
};

console.log('123');

// @ts-ignore
if(!window._HYDRATE) {
// это означает что скрипт загрузился быстрее
// потомучто скрипт пришел, а сервер еще не установил window._HYDRATE
// значит в этом случае бутстрап скрипт пришел вызов фнукции = <script>window._HYDRATE();</script>
// @ts-ignore
window._HYDRATE = hydrate;
} else {
// if shell loaded faster than script
// это означает что сервер уже установил window._HYDRATE = true = <script>window._HYDRATE = true</script>
hydrate();
}
4 changes: 4 additions & 0 deletions src/client/lazyTest.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.test {
color: red;
height: 10px;
}
15 changes: 15 additions & 0 deletions src/client/lazyTestcomponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

import './lazyTest.scss';
import { Image } from '@client/modules/components/shared/Image/Image';

const LazyTestcomponent = () => {
return (
<>
<Image src="123" alt='123' />
<div className="test">lazyTestcomponent</div>
</>
);
};

export default LazyTestcomponent;
3 changes: 1 addition & 2 deletions src/client/modules/components/global/NotFound/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React from 'react';

import { Flex, Image } from '@client/modules/components/shared';
import { Flex } from '@client/modules/components/shared';

import notFoundImg from './assets/404-error.png';

const NotFound = () => {
return (
<Flex customWidth='100%' flexDirection='column' alignItems='center'>
{/* TODO ADD ISOMORPHIC IMAGE COMPONENT wich solve static src problem */}
<Image src={notFoundImg} alt="Page not found" />
<h2>Oops! Page not found</h2>
</Flex>
);
Expand Down
3 changes: 3 additions & 0 deletions src/client/modules/components/shared/Image/Image.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.helloBundle {
color: '#04353';
}
10 changes: 4 additions & 6 deletions src/client/modules/components/shared/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React from 'react';

import {isNodeJS} from '@general-infrastructure/constants';
import './Image.scss';

type PropTypes = {
src: string;
alt: string;
}

const Image: React.FC<PropTypes> = ({
export const Image: React.FC<PropTypes> = ({
src,
alt,
}) => {
return (
<img src={src} alt={alt} />
<img className="helloBundle" src={src} alt={alt} />
);
};

export default Image;
};
1 change: 0 additions & 1 deletion src/client/modules/components/shared/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
export { default as Container } from './Container/Container';
export { default as Flex } from './Flex/Flex';
// export { default as Loader } from './Loader/Loader';
export { default as Image } from './Image/Image';
export { default as Wrap } from './Wrap/Wrap';
export * from './Link/Link';
4 changes: 3 additions & 1 deletion src/client/modules/pages/Lazy/Lazy.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react';
import { Image } from '@client/modules/components/shared/Image/Image';

import './huse.scss';

const LazyComponent = ({hello}: {hello: string}) => {
return (
<div className='hello'>
Lazy COMPONENT
<Image src="123" alt='123' />
Lazy COMPONENT
{hello}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.superPrivatePageCss {
color: red
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React from 'react';

// import './SuperPrivatePage.css';

export const SuperPrivatePage = () => {
return (
<div>Super private page</div>
<>
<div className='superPrivatePageCss'>Super private page</div>
</>
);
};

Expand Down
35 changes: 27 additions & 8 deletions src/client/modules/routes/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import LazyLoad from '@client/libs/LazyComponents/modules/LazyLoad/LazyLoad';
import PrivateRoute from './PrivateRoute';
import { DynamicModuleLoader } from '@client/libs/Microfrontends/DynamicModuleLoader';
import { HOMEPAGE_MICROFRONT } from '@client/constants/microfrontends';
import { dynamicLoad } from '@general-infrastructure/libs/dynamicLoad';

const SuperPrivatePage = React.lazy(
() => import(/* webpackChunkName: "SuperPrivatePageChunk" */
const SuperPrivatePage = dynamicLoad(
() => React.lazy(() => import(/* webpackChunkName: "SuperPrivatePageChunk" */
'@client/modules/pages/SuperPrivatePage/SuperPrivatePage'
),
)),
'SuperPrivatePageChunk',
);
const LazyLoadChunk = dynamicLoad(
() => React.lazy(() => import(/* webpackChunkName: "LazyLoadChunk" */ '@client/modules/pages/Lazy/Lazy')),
'LazyLoadChunk',
);

const Homepage = React.lazy(() => import('homePage/Homepage'));
Expand All @@ -19,13 +25,26 @@ const Routes: React.FC = () => {
[
{path: '/', element: <Feed />},
{path: '/lazy', element: (
<LazyLoad<{hello: string}>
render={(Component) => <Component hello="dfgd" />}
load={() => import(/* webpackChunkName: "LazyLoadChunk" */ '@client/modules/pages/Lazy/Lazy')}
/>
<Suspense fallback="loading">
{/* @ts-ignore */}
<LazyLoadChunk hello='dfgd' />
</Suspense>
)},
{path: '/overview', element: <Overview.component />},
{path: '/super-private-page', element: <PrivateRoute Component={SuperPrivatePage} />},
{path: '/super-private-page', element: (
<Suspense fallback="private">
{/* @ts-ignore */}
<PrivateRoute Component={SuperPrivatePage} />
</Suspense>
)},
{path: '/lazycss', element:
<LazyLoad
render={(Component) => <>
<Component />
</>}
load={() => import(/* webpackChunkName: "LazyTestComponent" */ '@client/lazyTestcomponent')}
/>,
},
{
path: '/microfronted/home',
element: (
Expand Down
1 change: 1 addition & 0 deletions src/client/styles/nullable.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
body {
margin: 0;
background-color: black;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {CssAssetsExtractorType, ImportedStatsType} from './chunkLoadingCollector.types';

type ChunkLoadingCollectorType = {
/**
* shouldBeLoadedStyles contains "webpackChunkName" keys
*/
shouldBeLoadedStyles: Set<string>;
// stats generated by 'webpack-imported' plugin
stats: ImportedStatsType;
collect: (chunkName: string) => void;
cssAssetsExtractor: CssAssetsExtractorType;
initStats: (stats: ImportedStatsType) => ChunkLoadingCollectorType;
};

/**
* ChunkLoadingCollector class which control 'really' loaded css chunks on ssr
*/
export class ChunkLoadingCollector implements ChunkLoadingCollectorType {
shouldBeLoadedStyles: Set<string> = new Set();
stats: ImportedStatsType;
cssAssetsExtractor: CssAssetsExtractorType;

/**
* constructor
* connect all methods to class context becuase we want to call it by itself
*/
constructor(cssAssetsExtractor: CssAssetsExtractorType) {
this.cssAssetsExtractor = cssAssetsExtractor;
this.collect = this.collect.bind(this);
this.extractStatsFromChunk = this.extractStatsFromChunk.bind(this);
this.initStats = this.initStats.bind(this);
}

/**
* extractStatsFromChunk method which extracts styles to load from stats
* @param chunkName
* @returns
*/
extractStatsFromChunk(chunkName: string[]) {
console.log('extractStatsFromChunk', this.cssAssetsExtractor, {
chunkName,
importedStats: Object.keys(this.stats),
chunkAssets: this.stats.chunks[chunkName[0]],
});
const {styles} = this.cssAssetsExtractor(this.stats, chunkName);

console.log({styles});

return styles.load;
}

/**
* collect method which used for jsut collecting "chunkName"'s stats
* @param chunkName
* @returns
*/
collect(...chunkName: string[]) {
try {
const stats = this.extractStatsFromChunk(chunkName);

if (!stats) return;

// to Load chunks
stats.forEach(chunk => {
this.shouldBeLoadedStyles.add(chunk);
});
} catch (error) {
if (process.env.NODE_ENV === 'development')
// eslint-disable-next-line no-console
console.error(`Some error occured in ChunkLoadingCollector`, {error});
}
}

/**
* initStats method which initialize stats for concrete build
* @param stats
* @returns
*/
initStats(stats: ImportedStatsType) {
// @TODO load all init bundle styles
// initially set means
this.stats = stats;
return this;
}
}
Loading