mirror of
https://github.com/kamranahmedse/developer-roadmap.git
synced 2026-03-16 11:51:49 +08:00
Compare commits
38 Commits
questions/
...
fix/auth-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0652286bf | ||
|
|
92d562baed | ||
|
|
7ba48523da | ||
|
|
c1ebe9ae47 | ||
|
|
415a9c0fd0 | ||
|
|
d3b8cbceaa | ||
|
|
c390f4428e | ||
|
|
2e890b1b25 | ||
|
|
7b9be9377b | ||
|
|
4863f08a4c | ||
|
|
81a14e90eb | ||
|
|
51dd58f7ed | ||
|
|
28a0fca90d | ||
|
|
be8495a60a | ||
|
|
cf5ac18aa1 | ||
|
|
0c7bc0e330 | ||
|
|
94ba9e7451 | ||
|
|
0de6ed6028 | ||
|
|
ef0c9f3db2 | ||
|
|
468e92bac1 | ||
|
|
733e9cb5af | ||
|
|
714ca8c49f | ||
|
|
63c3850f0e | ||
|
|
e2f7abe69a | ||
|
|
780402afd6 | ||
|
|
2b74f70ef9 | ||
|
|
1eab06f1f5 | ||
|
|
d2b7704370 | ||
|
|
a5d5f63677 | ||
|
|
dfc7821a44 | ||
|
|
1cee0b36dc | ||
|
|
0d1f916535 | ||
|
|
ce0f2a4ee4 | ||
|
|
bf89b013d1 | ||
|
|
5bcb3e282d | ||
|
|
747652c0f3 | ||
|
|
ed0e376d46 | ||
|
|
ef3e4fc3f3 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -30,4 +30,4 @@ tests-examples
|
||||
*.csv
|
||||
|
||||
/editor/*
|
||||
!/editor/readonly-editor.tsx
|
||||
!/editor/readonly-editor.tsx
|
||||
|
||||
36
package.json
36
package.json
@@ -22,38 +22,38 @@
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/react": "^3.0.8",
|
||||
"@astrojs/sitemap": "^3.0.3",
|
||||
"@astrojs/tailwind": "^5.0.4",
|
||||
"@astrojs/react": "^3.0.9",
|
||||
"@astrojs/sitemap": "^3.0.5",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@fingerprintjs/fingerprintjs": "^4.2.1",
|
||||
"@nanostores/react": "^0.7.1",
|
||||
"@types/react": "^18.2.45",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"astro": "^4.0.7",
|
||||
"astro-compress": "^2.2.3",
|
||||
"clsx": "^2.0.0",
|
||||
"astro": "^4.2.1",
|
||||
"astro-compress": "^2.2.8",
|
||||
"clsx": "^2.1.0",
|
||||
"dracula-prism": "^2.1.13",
|
||||
"jose": "^5.1.3",
|
||||
"jose": "^5.2.0",
|
||||
"js-cookie": "^3.0.5",
|
||||
"lucide-react": "^0.300.0",
|
||||
"nanoid": "^5.0.4",
|
||||
"nanostores": "^0.9.5",
|
||||
"node-html-parser": "^6.1.11",
|
||||
"node-html-parser": "^6.1.12",
|
||||
"npm-check-updates": "^16.14.12",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "^18.2.0",
|
||||
"react-confetti": "^6.1.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"reactflow": "^11.10.1",
|
||||
"reactflow": "^11.10.2",
|
||||
"rehype-external-links": "^3.0.0",
|
||||
"roadmap-renderer": "^1.0.6",
|
||||
"slugify": "^1.6.6",
|
||||
"tailwind-merge": "^2.2.0",
|
||||
"tailwindcss": "^3.4.0",
|
||||
"zustand": "^4.4.7"
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.40.1",
|
||||
"@playwright/test": "^1.41.1",
|
||||
"@tailwindcss/typography": "^0.5.10",
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"@types/prismjs": "^1.26.3",
|
||||
@@ -61,9 +61,9 @@
|
||||
"gh-pages": "^6.1.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"markdown-it": "^14.0.0",
|
||||
"openai": "^4.24.1",
|
||||
"prettier": "^3.1.1",
|
||||
"prettier-plugin-astro": "^0.12.2",
|
||||
"prettier-plugin-tailwindcss": "^0.5.9"
|
||||
"openai": "^4.25.0",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier-plugin-astro": "^0.12.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11"
|
||||
}
|
||||
}
|
||||
|
||||
2399
pnpm-lock.yaml
generated
2399
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/authors/fernando.jpeg
Normal file
BIN
public/authors/fernando.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
BIN
public/images/partners/spring-tile.png
Normal file
BIN
public/images/partners/spring-tile.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
BIN
public/pdfs/roadmaps/mlops.pdf
Normal file
BIN
public/pdfs/roadmaps/mlops.pdf
Normal file
Binary file not shown.
BIN
public/roadmaps/mlops.png
Normal file
BIN
public/roadmaps/mlops.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 288 KiB |
15
src/components/AppChecklist.tsx
Normal file
15
src/components/AppChecklist.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { PartyPopper } from 'lucide-react';
|
||||
|
||||
export function AppChecklist() {
|
||||
return (
|
||||
<div className="fixed bottom-6 right-3">
|
||||
<a
|
||||
href="/get-started"
|
||||
className="flex items-center gap-2 rounded-full border border-slate-900 bg-white py-2 pl-3 pr-4 text-sm font-medium hover:bg-zinc-200"
|
||||
>
|
||||
<PartyPopper className="relative -top-[2px] h-[20px] w-[20px] text-purple-600" />
|
||||
Welcome! Start here
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
41
src/components/AuthenticationFlow/AuthenticationForm.tsx
Normal file
41
src/components/AuthenticationFlow/AuthenticationForm.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import { useState } from 'react';
|
||||
import { GitHubButton } from './GitHubButton';
|
||||
import { GoogleButton } from './GoogleButton';
|
||||
import { LinkedInButton } from './LinkedInButton';
|
||||
import { EmailLoginForm } from './EmailLoginForm';
|
||||
import { EmailSignupForm } from './EmailSignupForm';
|
||||
|
||||
type AuthenticationFormProps = {
|
||||
type?: 'login' | 'signup';
|
||||
};
|
||||
|
||||
export function AuthenticationForm(props: AuthenticationFormProps) {
|
||||
const { type = 'login' } = props;
|
||||
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<GitHubButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
|
||||
<GoogleButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
|
||||
<LinkedInButton isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
|
||||
</div>
|
||||
|
||||
<div className="flex w-full items-center gap-2 py-6 text-sm text-slate-600">
|
||||
<div className="h-px w-full bg-slate-200" />
|
||||
OR
|
||||
<div className="h-px w-full bg-slate-200" />
|
||||
</div>
|
||||
|
||||
{type === 'login' ? (
|
||||
<EmailLoginForm isDisabled={isDisabled} setIsDisabled={setIsDisabled} />
|
||||
) : (
|
||||
<EmailSignupForm
|
||||
isDisabled={isDisabled}
|
||||
setIsDisabled={setIsDisabled}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -2,9 +2,16 @@ import Cookies from 'js-cookie';
|
||||
import type { FormEvent } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
|
||||
type EmailLoginFormProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
};
|
||||
|
||||
export function EmailLoginForm(props: EmailLoginFormProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
|
||||
export function EmailLoginForm() {
|
||||
const [email, setEmail] = useState<string>('');
|
||||
const [password, setPassword] = useState<string>('');
|
||||
const [error, setError] = useState('');
|
||||
@@ -14,6 +21,7 @@ export function EmailLoginForm() {
|
||||
const handleFormSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
setError('');
|
||||
|
||||
const { response, error } = await httpPost<{ token: string }>(
|
||||
@@ -26,11 +34,7 @@ export function EmailLoginForm() {
|
||||
|
||||
// Log the user in and reload the page
|
||||
if (response?.token) {
|
||||
Cookies.set(TOKEN_COOKIE_NAME, response.token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.reload();
|
||||
|
||||
return;
|
||||
@@ -45,6 +49,7 @@ export function EmailLoginForm() {
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
setError(error?.message || 'Something went wrong. Please try again later.');
|
||||
};
|
||||
|
||||
@@ -92,7 +97,7 @@ export function EmailLoginForm() {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isDisabled}
|
||||
className="inline-flex w-full items-center justify-center rounded-lg bg-black p-2 py-3 text-sm font-medium text-white outline-none focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:bg-gray-400"
|
||||
>
|
||||
{isLoading ? 'Please wait...' : 'Continue'}
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
import { type FormEvent, useState } from 'react';
|
||||
import { httpPost } from '../../lib/http';
|
||||
|
||||
export function EmailSignupForm() {
|
||||
type EmailSignupFormProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
};
|
||||
|
||||
export function EmailSignupForm(props: EmailSignupFormProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
|
||||
const [email, setEmail] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [name, setName] = useState('');
|
||||
@@ -13,6 +20,7 @@ export function EmailSignupForm() {
|
||||
e.preventDefault();
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
setError('');
|
||||
|
||||
const { response, error } = await httpPost<{ status: 'ok' }>(
|
||||
@@ -21,20 +29,21 @@ export function EmailSignupForm() {
|
||||
email,
|
||||
password,
|
||||
name,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (error || response?.status !== 'ok') {
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
setError(
|
||||
error?.message || 'Something went wrong. Please try again later.'
|
||||
error?.message || 'Something went wrong. Please try again later.',
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = `/verification-pending?email=${encodeURIComponent(
|
||||
email
|
||||
email,
|
||||
)}`;
|
||||
};
|
||||
|
||||
@@ -90,7 +99,7 @@ export function EmailSignupForm() {
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isDisabled}
|
||||
className="inline-flex w-full items-center justify-center rounded-lg bg-black p-2 py-3 text-sm font-medium text-white outline-none focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:bg-gray-400"
|
||||
>
|
||||
{isLoading ? 'Please wait...' : 'Continue to Verify Email'}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { GitHubIcon } from '../ReactIcons/GitHubIcon.tsx';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
|
||||
type GitHubButtonProps = {};
|
||||
type GitHubButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
};
|
||||
|
||||
const GITHUB_REDIRECT_AT = 'githubRedirectAt';
|
||||
const GITHUB_LAST_PAGE = 'githubLastPage';
|
||||
|
||||
export function GitHubButton(props: GitHubButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@@ -25,6 +30,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-github-callback${
|
||||
window.location.search
|
||||
@@ -35,6 +41,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
const errMessage = error?.message || 'Something went wrong.';
|
||||
setError(errMessage);
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -63,21 +70,19 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
|
||||
localStorage.removeItem(GITHUB_REDIRECT_AT);
|
||||
localStorage.removeItem(GITHUB_LAST_PAGE);
|
||||
Cookies.set(TOKEN_COOKIE_NAME, response.token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleClick = async () => {
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
|
||||
const { response, error } = await httpGet<{ loginUrl: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-github-login`,
|
||||
@@ -89,6 +94,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
);
|
||||
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -112,7 +118,7 @@ export function GitHubButton(props: GitHubButtonProps) {
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { GoogleIcon } from '../ReactIcons/GoogleIcon.tsx';
|
||||
|
||||
type GoogleButtonProps = {};
|
||||
type GoogleButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
};
|
||||
|
||||
const GOOGLE_REDIRECT_AT = 'googleRedirectAt';
|
||||
const GOOGLE_LAST_PAGE = 'googleLastPage';
|
||||
|
||||
export function GoogleButton(props: GoogleButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@@ -25,6 +30,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-google-callback${
|
||||
window.location.search
|
||||
@@ -34,6 +40,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
if (!response?.token) {
|
||||
setError(error?.message || 'Something went wrong.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -62,21 +69,19 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
|
||||
localStorage.removeItem(GOOGLE_REDIRECT_AT);
|
||||
localStorage.removeItem(GOOGLE_LAST_PAGE);
|
||||
Cookies.set(TOKEN_COOKIE_NAME, response.token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleClick = () => {
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ loginUrl: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-google-login`,
|
||||
)
|
||||
@@ -84,6 +89,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
if (!response?.loginUrl) {
|
||||
setError(error?.message || 'Something went wrong.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -106,6 +112,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -113,7 +120,7 @@ export function GoogleButton(props: GoogleButtonProps) {
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import { httpGet } from '../../lib/http';
|
||||
import { Spinner } from '../ReactIcons/Spinner.tsx';
|
||||
import { LinkedInIcon } from '../ReactIcons/LinkedInIcon.tsx';
|
||||
|
||||
type LinkedInButtonProps = {};
|
||||
type LinkedInButtonProps = {
|
||||
isDisabled?: boolean;
|
||||
setIsDisabled?: (isDisabled: boolean) => void;
|
||||
};
|
||||
|
||||
const LINKEDIN_REDIRECT_AT = 'linkedInRedirectAt';
|
||||
const LINKEDIN_LAST_PAGE = 'linkedInLastPage';
|
||||
|
||||
export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
const { isDisabled, setIsDisabled } = props;
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
@@ -25,6 +30,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ token: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-linkedin-callback${
|
||||
window.location.search
|
||||
@@ -34,6 +40,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
if (!response?.token) {
|
||||
setError(error?.message || 'Something went wrong.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -62,21 +69,19 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
|
||||
localStorage.removeItem(LINKEDIN_REDIRECT_AT);
|
||||
localStorage.removeItem(LINKEDIN_LAST_PAGE);
|
||||
Cookies.set(TOKEN_COOKIE_NAME, response.token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.href = redirectUrl;
|
||||
})
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const handleClick = () => {
|
||||
setIsLoading(true);
|
||||
setIsDisabled?.(true);
|
||||
httpGet<{ loginUrl: string }>(
|
||||
`${import.meta.env.PUBLIC_API_URL}/v1-linkedin-login`,
|
||||
)
|
||||
@@ -84,6 +89,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
if (!response?.loginUrl) {
|
||||
setError(error?.message || 'Something went wrong.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -106,6 +112,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
.catch((err) => {
|
||||
setError('Something went wrong. Please try again later.');
|
||||
setIsLoading(false);
|
||||
setIsDisabled?.(false);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -113,7 +120,7 @@ export function LinkedInButton(props: LinkedInButtonProps) {
|
||||
<>
|
||||
<button
|
||||
className="inline-flex h-10 w-full items-center justify-center gap-2 rounded border border-slate-300 bg-white p-2 text-sm font-medium text-black outline-none focus:ring-2 focus:ring-[#333] focus:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || isDisabled}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{isLoading ? (
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
---
|
||||
import Popup from '../Popup/Popup.astro';
|
||||
import { EmailLoginForm } from './EmailLoginForm';
|
||||
import Divider from './Divider.astro';
|
||||
import { GitHubButton } from './GitHubButton';
|
||||
import { GoogleButton } from './GoogleButton';
|
||||
import { LinkedInButton } from './LinkedInButton';
|
||||
import { AuthenticationForm } from './AuthenticationForm';
|
||||
---
|
||||
|
||||
<Popup id='login-popup' title='' subtitle=''>
|
||||
<div class='text-center'>
|
||||
<div class='mb-7 text-center'>
|
||||
<p class='mb-3 text-2xl font-semibold leading-5 text-slate-900'>
|
||||
Login to your account
|
||||
</p>
|
||||
@@ -16,19 +12,9 @@ import { LinkedInButton } from './LinkedInButton';
|
||||
You must be logged in to perform this action.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class='mt-7 flex flex-col gap-2'>
|
||||
<GitHubButton client:load />
|
||||
<GoogleButton client:load />
|
||||
<LinkedInButton client:load />
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<EmailLoginForm client:load />
|
||||
|
||||
<AuthenticationForm client:load />
|
||||
<div class='mt-6 text-center text-sm text-slate-600'>
|
||||
Don't have an account?{' '}
|
||||
<a href='/signup' class='font-medium text-[#4285f4]'>Sign up</a>
|
||||
<a href='/signup' class='font-medium text-[#4285f4]'> Sign up</a>
|
||||
</div>
|
||||
</Popup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { type FormEvent, useEffect, useState } from 'react';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
|
||||
export function ResetPasswordForm() {
|
||||
const [code, setCode] = useState('');
|
||||
@@ -37,7 +37,7 @@ export function ResetPasswordForm() {
|
||||
newPassword: password,
|
||||
confirmPassword: passwordConfirm,
|
||||
code,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (error?.message) {
|
||||
@@ -53,11 +53,7 @@ export function ResetPasswordForm() {
|
||||
}
|
||||
|
||||
const token = response.token;
|
||||
Cookies.set(TOKEN_COOKIE_NAME, token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.href = '/';
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Cookies from 'js-cookie';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, setAuthToken } from '../../lib/jwt';
|
||||
import { Spinner } from '../ReactIcons/Spinner';
|
||||
import { ErrorIcon2 } from '../ReactIcons/ErrorIcon2';
|
||||
|
||||
@@ -26,11 +26,7 @@ export function TriggerVerifyAccount() {
|
||||
return;
|
||||
}
|
||||
|
||||
Cookies.set(TOKEN_COOKIE_NAME, response.token, {
|
||||
path: '/',
|
||||
expires: 30,
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
setAuthToken(response.token);
|
||||
window.location.href = '/';
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
@@ -101,22 +101,10 @@ export function CustomRoadmap(props: CustomRoadmapProps) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
async function trackVisit() {
|
||||
if (!isLoggedIn() || isEmbed) {
|
||||
return;
|
||||
}
|
||||
|
||||
await httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-visit`, {
|
||||
resourceId: id,
|
||||
resourceType: 'roadmap',
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getRoadmap().finally(() => {
|
||||
hideRoadmapLoader();
|
||||
});
|
||||
trackVisit().then();
|
||||
}, []);
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -117,19 +117,6 @@ export class Renderer {
|
||||
});
|
||||
}
|
||||
|
||||
trackVisit() {
|
||||
if (!isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-visit`, {
|
||||
resourceId: this.resourceId,
|
||||
resourceType: this.resourceType,
|
||||
}).then(() => null);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
onDOMLoaded() {
|
||||
if (!this.prepareConfig()) {
|
||||
return;
|
||||
@@ -138,8 +125,6 @@ export class Renderer {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const roadmapType = urlParams.get('r');
|
||||
|
||||
this.trackVisit();
|
||||
|
||||
if (roadmapType) {
|
||||
this.switchRoadmap(`/${roadmapType}.json`);
|
||||
} else {
|
||||
|
||||
78
src/components/GetStarted/RoadmapCard.tsx
Normal file
78
src/components/GetStarted/RoadmapCard.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ExternalLink, Globe2, type LucideIcon } from 'lucide-react';
|
||||
|
||||
type RoadmapCardProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
icon: LucideIcon;
|
||||
icon2?: LucideIcon;
|
||||
link: string;
|
||||
isUpcoming?: boolean;
|
||||
};
|
||||
export function RoadmapCard(props: RoadmapCardProps) {
|
||||
const {
|
||||
isUpcoming,
|
||||
link,
|
||||
title,
|
||||
description,
|
||||
icon: Icon,
|
||||
icon2: Icon2,
|
||||
} = props;
|
||||
|
||||
if (isUpcoming) {
|
||||
return (
|
||||
<div className="group relative block rounded-xl border border-gray-300 bg-gradient-to-br from-gray-100 to-gray-50 p-5 overflow-hidden">
|
||||
<div className="mb-2 sm:mb-5 flex flex-row items-center">
|
||||
<div className="flex h-7 w-7 sm:h-9 sm:w-9 items-center justify-center rounded-full bg-gray-900 text-white">
|
||||
<Icon className="h-3 sm:h-5" />
|
||||
</div>
|
||||
{Icon2 && (
|
||||
<>
|
||||
<span className="mx-2 text-gray-400">+</span>
|
||||
<div className="flex h-7 w-7 sm:h-9 sm:w-9 items-center justify-center rounded-full bg-gray-900 text-white">
|
||||
<Icon2 className="h-3 sm:h-5" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<span className="mb-0.5 block text-lg sm:text-xl font-semibold sm:mb-2">
|
||||
{title}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500">{description}</span>
|
||||
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center bg-gray-100/70">
|
||||
<span className="text-sm bg-black rounded-lg text-white font-semibold py-1 px-2 -rotate-45 transform">
|
||||
Coming soon
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<a
|
||||
href={link}
|
||||
target={'_blank'}
|
||||
className="group relative block rounded-xl border border-gray-300 bg-gradient-to-br from-gray-100 to-gray-50
|
||||
p-3.5 sm:p-5 transition-colors duration-200 ease-in-out hover:cursor-pointer hover:border-black/30 hover:bg-gray-50/70 hover:shadow-sm"
|
||||
>
|
||||
<div className="mb-2 sm:mb-5 flex flex-row items-center">
|
||||
<div className="flex h-7 w-7 sm:h-9 sm:w-9 items-center justify-center rounded-full bg-gray-900 text-white">
|
||||
<Icon className="h-4 sm:h-5" />
|
||||
</div>
|
||||
{Icon2 && (
|
||||
<>
|
||||
<span className="mx-2 text-gray-400">+</span>
|
||||
<div className="flex h-7 w-7 sm:h-9 sm:w-9 items-center justify-center rounded-full bg-gray-900 text-white">
|
||||
<Icon2 className="h-4 sm:h-5" />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<ExternalLink className="lucide lucide-external-link absolute right-2 top-2 h-4 text-gray-300 transition group-hover:text-gray-700" />
|
||||
<span className="mb-0 block text-lg sm:text-xl font-semibold sm:mb-2">
|
||||
{title}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500">{description}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
63
src/components/GetStarted/RoadmapMultiCard.tsx
Normal file
63
src/components/GetStarted/RoadmapMultiCard.tsx
Normal file
@@ -0,0 +1,63 @@
|
||||
import { ExternalLink } from 'lucide-react';
|
||||
|
||||
type RoadmapMultiCardProps = {
|
||||
roadmaps: {
|
||||
title: string;
|
||||
link: string;
|
||||
}[];
|
||||
description: string;
|
||||
secondaryRoadmaps?: {
|
||||
title: string;
|
||||
link: string;
|
||||
}[];
|
||||
secondaryDescription?: string;
|
||||
};
|
||||
export function RoadmapMultiCard(props: RoadmapMultiCardProps) {
|
||||
const { roadmaps, description, secondaryRoadmaps, secondaryDescription } = props;
|
||||
return (
|
||||
<div
|
||||
className="relative flex flex-col overflow-hidden rounded-xl border border-gray-300 bg-gradient-to-br from-gray-100
|
||||
to-gray-50 ease-in-out"
|
||||
>
|
||||
<div className="flex flex-col divide-y">
|
||||
{roadmaps.map((roadmap, index) => (
|
||||
<a
|
||||
target={'_blank'}
|
||||
key={index}
|
||||
href={roadmap.link}
|
||||
className="group text-sm sm:text-base flex w-full items-center justify-between gap-2 bg-gradient-to-br from-gray-100 to-gray-50 px-4 sm:px-5 py-2 transition-colors duration-200"
|
||||
>
|
||||
{roadmap.title}
|
||||
<ExternalLink className="lucide lucide-external-link h-4 text-gray-300 transition group-hover:text-gray-700" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<p className="flex-grow bg-gray-200/70 p-4 sm:p-5 text-sm text-gray-500">
|
||||
{description}
|
||||
</p>
|
||||
|
||||
{secondaryRoadmaps && (
|
||||
<div className="flex flex-col divide-y">
|
||||
{secondaryRoadmaps.map((roadmap, index) => (
|
||||
<a
|
||||
target={'_blank'}
|
||||
key={index}
|
||||
href={roadmap.link}
|
||||
className="group text-sm sm:text-base flex w-full items-center justify-between gap-2 bg-gradient-to-br from-gray-100 to-gray-50 px-5 py-2 transition-colors duration-200"
|
||||
>
|
||||
{roadmap.title}
|
||||
<ExternalLink className="lucide lucide-external-link h-4 text-gray-300 transition group-hover:text-gray-700" />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{secondaryDescription && (
|
||||
<p className="flex-grow bg-gray-200/70 p-4 sm:p-5 text-sm text-gray-500">
|
||||
{secondaryDescription}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
29
src/components/GetStarted/RoleRoadmaps.tsx
Normal file
29
src/components/GetStarted/RoleRoadmaps.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import { type ReactNode } from 'react';
|
||||
import { SectionBadge } from './SectionBadge.tsx';
|
||||
|
||||
type RoleRoadmapsProps = {
|
||||
badge: string;
|
||||
title: string;
|
||||
description: string;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export function RoleRoadmaps(props: RoleRoadmapsProps) {
|
||||
const { badge, title, description, children } = props;
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-b from-gray-100 to-white py-5 sm:py-8 md:py-12">
|
||||
<div className="container">
|
||||
<div className="text-left">
|
||||
<SectionBadge title={badge} />
|
||||
</div>
|
||||
<div className="my-4 sm:my-7 text-left">
|
||||
<h2 className="mb-1 text-xl sm:text-3xl font-semibold">{title}</h2>
|
||||
<p className="text-sm sm:text-base text-gray-500">{description}</p>
|
||||
|
||||
<div className="mt-4 sm:mt-7 grid sm:grid-cols-2 md:grid-cols-3 gap-3">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
12
src/components/GetStarted/SectionBadge.tsx
Normal file
12
src/components/GetStarted/SectionBadge.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
type SectionBadgeProps = {
|
||||
title: string;
|
||||
};
|
||||
export function SectionBadge(props: SectionBadgeProps) {
|
||||
const { title } = props;
|
||||
|
||||
return (
|
||||
<span className="rounded-full bg-black px-3 py-1 text-sm text-white">
|
||||
{title}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
31
src/components/GetStarted/TipItem.tsx
Normal file
31
src/components/GetStarted/TipItem.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
type TipItemProps = {
|
||||
title: string;
|
||||
description: string;
|
||||
};
|
||||
export function TipItem(props: TipItemProps) {
|
||||
const { title, description } = props;
|
||||
|
||||
const [isToggled, setIsToggled] = useState(false);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
{!isToggled && (
|
||||
<div
|
||||
onClick={() => setIsToggled(true)}
|
||||
className="cursor-pointer rounded-lg sm:rounded-xl bg-black px-3 py-2 text-sm sm:text-base text-white"
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
{isToggled && (
|
||||
<p
|
||||
className="rounded-lg sm:rounded-xl bg-gray-200 px-3 py-2 text-black text-sm sm:text-base"
|
||||
>
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -121,7 +121,7 @@ export function HeroRoadmaps(props: ProgressListProps) {
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 md:grid-cols-3">
|
||||
{progress.map((resource) => (
|
||||
<HeroRoadmap
|
||||
key={resource.resourceId}
|
||||
key={`${resource.resourceType}-${resource.resourceId}`}
|
||||
resourceId={resource.resourceId}
|
||||
resourceType={resource.resourceType}
|
||||
resourceTitle={resource.resourceTitle}
|
||||
|
||||
@@ -1,61 +1,38 @@
|
||||
---
|
||||
import { Menu } from 'lucide-react';
|
||||
import Icon from '../AstroIcon.astro';
|
||||
import { NavigationDropdown } from '../NavigationDropdown';
|
||||
import { AccountDropdown } from './AccountDropdown';
|
||||
---
|
||||
|
||||
<div class='bg-slate-900 py-5 text-white sm:py-8'>
|
||||
<nav class='container flex items-center justify-between'>
|
||||
<a
|
||||
class='flex items-center text-lg font-medium text-white'
|
||||
href='/'
|
||||
aria-label='roadmap.sh'
|
||||
>
|
||||
<Icon icon='logo' />
|
||||
</a>
|
||||
<div class='flex items-center gap-5'>
|
||||
<a
|
||||
class='flex items-center text-lg font-medium text-white'
|
||||
href='/'
|
||||
aria-label='roadmap.sh'
|
||||
>
|
||||
<Icon icon='logo' />
|
||||
</a>
|
||||
|
||||
<!-- Desktop navigation items -->
|
||||
<ul class='hidden space-x-5 sm:flex sm:items-center'>
|
||||
<li>
|
||||
<a href='/roadmaps' class='text-gray-400 hover:text-white'>Roadmaps</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='/best-practices' class='text-gray-400 hover:text-white'
|
||||
>Best Practices</a
|
||||
>
|
||||
</li>
|
||||
<li class='hidden xl:inline'>
|
||||
<a href='/questions' class='text-gray-400 hover:text-white'>Questions</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href='/teams' class='group relative text-blue-300 hover:text-white'>
|
||||
Teams
|
||||
<span
|
||||
class='ml-0.5 hidden rounded-sm border-black bg-blue-300 px-1 py-0.5 text-xs font-semibold uppercase text-black group-hover:bg-white md:inline'
|
||||
>
|
||||
New
|
||||
</span>
|
||||
|
||||
<span class='inline md:hidden absolute -right-[11px] top-0'>
|
||||
<span class='relative flex h-2 w-2'>
|
||||
<span
|
||||
class='absolute inline-flex h-full w-full animate-ping rounded-full bg-sky-400 opacity-75'
|
||||
></span>
|
||||
<span class='relative inline-flex h-2 w-2 rounded-full bg-sky-500'
|
||||
></span>
|
||||
</span>
|
||||
</span>
|
||||
<!-- Desktop navigation items -->
|
||||
<div class='hidden space-x-5 sm:flex sm:items-center'>
|
||||
<NavigationDropdown client:load />
|
||||
<a href='/get-started' class='text-gray-400 hover:text-white'>
|
||||
Start Here
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<kbd
|
||||
<a href='/teams' class='text-gray-400 hover:text-white'> Teams</a>
|
||||
<button
|
||||
data-command-menu
|
||||
class='hidden items-center rounded-md border border-gray-800 px-2.5 py-1 text-sm text-gray-400 hover:cursor-pointer hover:bg-gray-800 sm:flex'
|
||||
class='hidden items-center rounded-md border border-gray-800 px-2.5 py-1.5 text-sm text-gray-400 hover:cursor-pointer hover:bg-gray-800 sm:flex'
|
||||
>
|
||||
<Icon icon='search' class='mr-2 h-3 w-3' />
|
||||
<kbd class='mr-1 font-sans'>⌘</kbd><kbd class='font-sans'>K</kbd>
|
||||
</kbd>
|
||||
</li>
|
||||
</ul>
|
||||
<Icon icon='search' class='h-3 w-3' />
|
||||
<span class='ml-2'>Search</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class='hidden h-8 w-[172px] items-center justify-end gap-5 sm:flex'>
|
||||
<li data-guest-required class='hidden'>
|
||||
<a href='/login' class='text-gray-400 hover:text-white'>Login</a>
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, removeAuthToken } from '../../lib/jwt';
|
||||
|
||||
export function logout() {
|
||||
Cookies.remove(TOKEN_COOKIE_NAME, {
|
||||
path: '/',
|
||||
domain: import.meta.env.DEV ? 'localhost' : '.roadmap.sh',
|
||||
});
|
||||
removeAuthToken();
|
||||
|
||||
// Reloading will automatically redirect the user if required
|
||||
window.location.reload();
|
||||
|
||||
105
src/components/NavigationDropdown.tsx
Normal file
105
src/components/NavigationDropdown.tsx
Normal file
@@ -0,0 +1,105 @@
|
||||
import {
|
||||
BookOpen,
|
||||
BookOpenText,
|
||||
CheckSquare,
|
||||
FileQuestion,
|
||||
Menu,
|
||||
Shirt,
|
||||
Video,
|
||||
Waypoints,
|
||||
} from 'lucide-react';
|
||||
import { useRef, useState } from 'react';
|
||||
import { cn } from '../lib/classname.ts';
|
||||
import { useOutsideClick } from '../hooks/use-outside-click.ts';
|
||||
|
||||
const links = [
|
||||
{
|
||||
link: '/roadmaps',
|
||||
label: 'Roadmaps',
|
||||
description: 'Step by step learning paths',
|
||||
Icon: Waypoints,
|
||||
},
|
||||
{
|
||||
link: '/best-practices',
|
||||
label: 'Best Practices',
|
||||
description: "Do's and don'ts",
|
||||
Icon: CheckSquare,
|
||||
},
|
||||
{
|
||||
link: '/questions',
|
||||
label: 'Questions',
|
||||
description: 'Test and Practice your knowledge',
|
||||
Icon: FileQuestion,
|
||||
},
|
||||
{
|
||||
link: '/guides',
|
||||
label: 'Guides',
|
||||
description: 'In-depth articles and tutorials',
|
||||
Icon: BookOpenText,
|
||||
},
|
||||
{
|
||||
link: 'https://youtube.com/@roadmapsh',
|
||||
label: 'Videos',
|
||||
description: 'Animated and interactive content',
|
||||
Icon: Video,
|
||||
isExternal: true,
|
||||
},
|
||||
{
|
||||
link: 'https://cottonbureau.com/people/roadmapsh',
|
||||
label: 'Shop',
|
||||
description: 'Get some cool swag',
|
||||
Icon: Shirt,
|
||||
isExternal: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function NavigationDropdown() {
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
useOutsideClick(dropdownRef, () => {
|
||||
setIsOpen(false);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="relative flex items-center" ref={dropdownRef}>
|
||||
<button
|
||||
className={cn('text-gray-400 hover:text-white', {
|
||||
'text-white': isOpen,
|
||||
})}
|
||||
onClick={() => setIsOpen(true)}
|
||||
onMouseOver={() => setIsOpen(true)}
|
||||
>
|
||||
<Menu className="h-5 w-5" />
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
'absolute pointer-events-none left-0 top-full z-[999] mt-2 w-48 min-w-[320px] -translate-y-1 rounded-lg bg-slate-800 py-2 opacity-0 shadow-xl transition-all duration-100',
|
||||
{
|
||||
'pointer-events-auto translate-y-2.5 opacity-100': isOpen,
|
||||
},
|
||||
)}
|
||||
>
|
||||
{links.map((link) => (
|
||||
<a
|
||||
href={link.link}
|
||||
target={link.isExternal ? '_blank' : undefined}
|
||||
rel={link.isExternal ? 'noopener noreferrer' : undefined}
|
||||
key={link.link}
|
||||
className="group flex items-center gap-3 px-4 py-2.5 text-gray-400 transition-colors hover:bg-slate-700"
|
||||
>
|
||||
<span className="flex h-[40px] w-[40px] items-center justify-center rounded-full bg-slate-600 transition-colors group-hover:bg-slate-500 group-hover:text-slate-100">
|
||||
<link.Icon className="inline-block h-5 w-5" />
|
||||
</span>
|
||||
<span className="flex flex-col">
|
||||
<span className="font-medium text-slate-300 transition-colors group-hover:text-slate-100">
|
||||
{link.label}
|
||||
</span>
|
||||
<span className="text-sm">{link.description}</span>
|
||||
</span>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
25
src/components/PageVisit/PageVisit.tsx
Normal file
25
src/components/PageVisit/PageVisit.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { useEffect } from 'react';
|
||||
import { isLoggedIn } from '../../lib/jwt';
|
||||
import { httpPost } from '../../lib/http';
|
||||
import type { ResourceType } from '../../lib/resource-progress';
|
||||
|
||||
type PageVisitProps = {
|
||||
resourceId?: string;
|
||||
resourceType?: ResourceType;
|
||||
};
|
||||
|
||||
export function PageVisit(props: PageVisitProps) {
|
||||
const { resourceId, resourceType } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoggedIn()) {
|
||||
return;
|
||||
}
|
||||
|
||||
httpPost(`${import.meta.env.PUBLIC_API_URL}/v1-visit`, {
|
||||
...(resourceType && { resourceType, resourceId }),
|
||||
}).finally(() => {});
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,31 +1,33 @@
|
||||
import {AlertTriangle, Barcode, BookOpenIcon, PieChart, Shrub, SquareIcon, UserRoundPlus} from "lucide-react";
|
||||
|
||||
const toolsList = [
|
||||
{
|
||||
imageUrl: '/images/team-promo/growth-plans.png',
|
||||
icon: Shrub,
|
||||
title: 'Growth plans',
|
||||
description: 'Prepare shared or individual growth plans for members.',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/team-promo/progress-tracking.png',
|
||||
icon: Barcode,
|
||||
title: 'Progress tracking',
|
||||
description: 'Track and compare the progress of team members.',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/team-promo/onboarding.png',
|
||||
icon: UserRoundPlus,
|
||||
title: 'Onboarding',
|
||||
description: 'Prepare onboarding plans for new team members.',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/team-promo/team-insights.png',
|
||||
icon: PieChart,
|
||||
title: 'Team insights',
|
||||
description: 'Get insights about your team skills, progress and more.',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/team-promo/skill-gap.png',
|
||||
icon: AlertTriangle,
|
||||
title: 'Skill gap analysis',
|
||||
description: 'Understand the skills of your team and identify gaps.',
|
||||
},
|
||||
{
|
||||
imageUrl: '/images/team-promo/documentation.png',
|
||||
icon: BookOpenIcon,
|
||||
title: 'Documentation',
|
||||
description: 'Create and share visual team documentation.',
|
||||
},
|
||||
@@ -44,11 +46,9 @@ export function TeamTools() {
|
||||
{toolsList.map((tool) => {
|
||||
return (
|
||||
<div className="rounded-md sm:rounded-xl border p-2 sm:p-5 text-left sm:text-center md:text-left">
|
||||
<img
|
||||
alt={tool.title}
|
||||
src={tool.imageUrl}
|
||||
className="mb-5 h-48 hidden sm:block mx-auto md:mx-0"
|
||||
/>
|
||||
<div className='mb-5 flex h-9 w-9 items-center justify-center rounded-full bg-gray-900 text-white'>
|
||||
{tool.icon ? <tool.icon size={23} /> : <SquareIcon size={24} /> }
|
||||
</div>
|
||||
<h3 className="mb-0.5 sm:mb-2 text-lg sm:text-2xl font-bold">{tool.title}</h3>
|
||||
<p className='text-sm sm:text-base'>{tool.description}</p>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import { type ChangeEvent, type FormEvent, useEffect, useRef, useState } from 'react';
|
||||
import { TOKEN_COOKIE_NAME } from '../../lib/jwt';
|
||||
import { TOKEN_COOKIE_NAME, removeAuthToken } from '../../lib/jwt';
|
||||
|
||||
interface PreviewFile extends File {
|
||||
preview: string;
|
||||
@@ -128,7 +128,7 @@ export default function UploadProfilePicture(props: UploadProfilePictureProps) {
|
||||
|
||||
// Logout user if token is invalid
|
||||
if (data.status === 401) {
|
||||
Cookies.remove(TOKEN_COOKIE_NAME);
|
||||
removeAuthToken();
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
- [GPU accelerated JavaScript](https://gpu.rocks/#/)
|
||||
- [Introducing Partytown 🎉: Run Third-Party Scripts From a Web Worker](https://dev.to/adamdbradley/introducing-partytown-run-third-party-scripts-from-a-web-worker-2cnp)
|
||||
- [Astro: Astro is a fresh but familiar approach to building websites. Astro combines decades of proven performance best practices with the DX improvements of the component-oriented era. Use your favorite JavaScript framework and automatically ship the bare-minimum amount of JavaScript—by default.](https://docs.astro.build/getting-started/)
|
||||
- [Minimising Layout and Layout thrashing for 60 FPS](https://www.charistheo.io/blog/2021/09/dom-reflow-and-layout-thrashing/)
|
||||
- [Minimising Layout and Layout thrashing for 60 FPS](https://www.harrytheo.com/blog/2021/09/dom-reflow-and-layout-thrashing/)
|
||||
- [Does shadow DOM improve style performance?](https://nolanlawson.com/2021/08/15/does-shadow-dom-improve-style-performance/)
|
||||
- [Debugging memory leaks - HTTP 203](https://www.youtube.com/watch?v=YDU_3WdfkxA)
|
||||
- [Explore JavaScript Dependencies With Lighthouse Treemap](https://sia.codes/posts/lighthouse-treemap/)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
title: 'The 5 Best Backend Development Languages to Master (2024)'
|
||||
description: 'Discover the best backend development languages to master in 2024.'
|
||||
author:
|
||||
name: 'Kamran Ahmed'
|
||||
url: 'https://twitter.com/kamrify'
|
||||
imageUrl: '/authors/kamranahmedse.jpeg'
|
||||
name: 'Fernando Doglio'
|
||||
url: 'https://twitter.com/deleteman123'
|
||||
imageUrl: '/authors/fernando.jpeg'
|
||||
excludedBySlug: '/backend/languages'
|
||||
seo:
|
||||
title: 'The 5 Best Backend Development Languages to Master (2024)'
|
||||
|
||||
@@ -4,7 +4,7 @@ briefTitle: 'JavaScript'
|
||||
briefDescription: 'Test, rate and improve your JavaScript knowledge with these questions.'
|
||||
title: 'JavaScript Questions'
|
||||
description: 'Test, rate and improve your JavaScript knowledge with these questions.'
|
||||
isNew: true
|
||||
isNew: false
|
||||
seo:
|
||||
title: 'JavaScript Questions'
|
||||
description: 'Curated list of JavaScript questions to test, rate and improve your knowledge. Questions are based on real world experience and knowledge.'
|
||||
|
||||
17
src/data/question-groups/nodejs/content/commonjs-vs-esm.md
Normal file
17
src/data/question-groups/nodejs/content/commonjs-vs-esm.md
Normal file
@@ -0,0 +1,17 @@
|
||||
CommonJS and ES Modules are two different module systems in JavaScript. CommonJS is the module system used in Node.js, while ES Modules are the module system used in browsers and TypeScript.
|
||||
|
||||
## CommonJS
|
||||
|
||||
```js
|
||||
const fs = require('fs');
|
||||
```
|
||||
|
||||
CommonJS modules are loaded synchronously. This means that the module is loaded and evaluated before the code using the module is executed. It uses `require()` to load modules and `module.exports` to export modules.
|
||||
|
||||
## ES Modules
|
||||
|
||||
```js
|
||||
import fs from 'fs';
|
||||
```
|
||||
|
||||
ES Modules are loaded asynchronously. This means that the module is loaded and evaluated when the module is used. It uses `import` to load modules and `export` to export modules.
|
||||
66
src/data/question-groups/nodejs/content/error-handling.md
Normal file
66
src/data/question-groups/nodejs/content/error-handling.md
Normal file
@@ -0,0 +1,66 @@
|
||||
There are four fundamental strategies to report errors in Node.js:
|
||||
|
||||
## `try...catch` blocks
|
||||
|
||||
`try...catch` blocks are the most basic way to handle errors in JavaScript. They are synchronous and can only be used to handle errors in synchronous code. They are not suitable for asynchronous code, such as callbacks and promises.
|
||||
|
||||
```js
|
||||
import fs from 'node:fs';
|
||||
|
||||
try {
|
||||
const data = fs.readFileSync('file.md', 'utf-8');
|
||||
console.log(data);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
```
|
||||
|
||||
## Callbacks
|
||||
|
||||
Callbacks are the most common way to handle errors in asynchronous code. They are passed as the last argument to a function and are called when the function completes or fails.
|
||||
|
||||
```js
|
||||
import fs from 'node:fs';
|
||||
|
||||
fs.readFile('file.md', 'utf-8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(data);
|
||||
});
|
||||
```
|
||||
|
||||
## Promises
|
||||
|
||||
Promises are a more modern way to handle errors in asynchronous code. They are returned by functions and can be chained together. They are resolved when the function completes and rejected when it fails.
|
||||
|
||||
```js
|
||||
import fs from 'node:fs/promises';
|
||||
|
||||
fs.readFile('file.md', 'utf-8')
|
||||
.then((data) => {
|
||||
console.log(data);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
|
||||
## Event emitters
|
||||
|
||||
Event emitters are a more advanced way to handle errors in asynchronous code. They are returned by functions and emit an `error` event when they fail. They are resolved when the function completes and rejected when it fails.
|
||||
|
||||
```js
|
||||
import fs from 'node:fs';
|
||||
|
||||
const reader = fs.createReadStream('file.md', 'utf-8');
|
||||
reader.on('data', (data) => {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
reader.on('error', (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
```
|
||||
18
src/data/question-groups/nodejs/content/exit-codes.md
Normal file
18
src/data/question-groups/nodejs/content/exit-codes.md
Normal file
@@ -0,0 +1,18 @@
|
||||
The following exit codes are used in Node.js:
|
||||
|
||||
- `0`: Success
|
||||
- `1`: Uncaught Fatal Exception
|
||||
- `2`: Unused
|
||||
- `3`: Internal JavaScript Parse Error
|
||||
- `4`: Internal JavaScript Evaluation Failure
|
||||
- `5`: Fatal Error
|
||||
- `6`: Non-function Internal Exception Handler
|
||||
- `7`: Internal Exception Handler Run-Time Failure
|
||||
- `8`: Unused
|
||||
- `9`: Invalid Argument
|
||||
- `10`: Internal JavaScript Run-Time Failure
|
||||
- `12`: Invalid Debug Argument
|
||||
- `13`: Uncaught Exception
|
||||
- `14`: Unhandled Promise Rejection
|
||||
- `15`: Fatal Exception
|
||||
- `16`: Signal Exits
|
||||
@@ -0,0 +1,18 @@
|
||||
In order to take user input from the command line, you can use the `readline` module. It provides an interface for reading data from a Readable stream (such as `process.stdin`) one line at a time.
|
||||
|
||||
```js
|
||||
import readline from 'node:readline';
|
||||
import { stdin as input, stdout as output } from 'node:process';
|
||||
|
||||
const rl = readline.createInterface({ input, output });
|
||||
|
||||
rl.question('What do you think of Node.js? ', (answer) => {
|
||||
console.log(`Thank you for your valuable feedback: ${answer}`);
|
||||
rl.close();
|
||||
});
|
||||
|
||||
rl.on('close', () => {
|
||||
console.log('\nBYE BYE !!!');
|
||||
process.exit(0);
|
||||
});
|
||||
```
|
||||
25
src/data/question-groups/nodejs/content/order-priority.md
Normal file
25
src/data/question-groups/nodejs/content/order-priority.md
Normal file
@@ -0,0 +1,25 @@
|
||||
Order priorities of `process.nextTick`, `Promise`, `setTimeout` and `setImmediate` are as follows:
|
||||
|
||||
1. `process.nextTick`: Highest priority, executed immediately after the current event loop cycle, before any other I/O events or timers.
|
||||
2. `Promise`: Executed in the microtask queue, after the current event loop cycle, but before the next one.
|
||||
3. `setTimeout`: Executed in the timer queue, after the current event loop cycle, with a minimum delay specified in milliseconds.
|
||||
4. `setImmediate`: Executed in the check queue, but its order may vary based on the system and load. It generally runs in the next iteration of the event loop after I/O events.
|
||||
|
||||
```js
|
||||
console.log('start');
|
||||
Promise.resolve().then(() => console.log('Promise'));
|
||||
setTimeout(() => console.log('setTimeout'), 0);
|
||||
process.nextTick(() => console.log('process.nextTick'));
|
||||
setImmediate(() => console.log('setImmediate'));
|
||||
console.log('end');
|
||||
|
||||
// Output:
|
||||
// start
|
||||
// end
|
||||
// process.nextTick
|
||||
// Promise
|
||||
// setTimeout
|
||||
// setImmediate
|
||||
```
|
||||
|
||||
In summary, the order of execution is generally `process.nextTick` > `Promise` > `setTimeout` > `setImmediate`. However, keep in mind that the behavior may vary in specific situations, and the order might be influenced by factors such as system load and other concurrent operations.
|
||||
15
src/data/question-groups/nodejs/content/process-argv.md
Normal file
15
src/data/question-groups/nodejs/content/process-argv.md
Normal file
@@ -0,0 +1,15 @@
|
||||
`process.argv` is an array containing the command-line arguments passed when the Node.js process was launched. The first element is the path to the Node.js executable, the second element is the path to the JavaScript file being executed, and the remaining elements are the command-line arguments.
|
||||
|
||||
```js
|
||||
node index.js hello world
|
||||
```
|
||||
|
||||
```js
|
||||
console.log(process.argv);
|
||||
// [
|
||||
// '/usr/local/bin/node', -> path to the Node.js executable
|
||||
// '/Users/username/projects/nodejs/index.js', -> path to the JavaScript file being executed
|
||||
// 'hello', -> command-line argument
|
||||
// 'world' -> command-line argument
|
||||
// ]
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
`process.cwd()` returns the current working directory of the Node.js process, while `__dirname` returns the directory name of the current module.
|
||||
|
||||
```js
|
||||
console.log(process.cwd());
|
||||
// /Users/username/projects/nodejs
|
||||
|
||||
console.log(__dirname);
|
||||
// /Users/username/projects/nodejs/src
|
||||
```
|
||||
14
src/data/question-groups/nodejs/content/web-server.md
Normal file
14
src/data/question-groups/nodejs/content/web-server.md
Normal file
@@ -0,0 +1,14 @@
|
||||
To create a minimal `Hello, World!` HTTP server in Node.js, you can use the `http` module. It provides an HTTP server, and the createServer() method sets up a server instance with a callback function to handle incoming requests
|
||||
|
||||
```js
|
||||
import http from 'node:http';
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Hello World\n');
|
||||
});
|
||||
|
||||
server.listen(3000, () => {
|
||||
console.log('Server running at http://localhost:3000/');
|
||||
});
|
||||
```
|
||||
227
src/data/question-groups/nodejs/nodejs.md
Normal file
227
src/data/question-groups/nodejs/nodejs.md
Normal file
@@ -0,0 +1,227 @@
|
||||
---
|
||||
order: 1
|
||||
briefTitle: 'Node.js'
|
||||
briefDescription: 'Test, rate and improve your Node.js knowledge with these questions.'
|
||||
title: 'Node.js Questions'
|
||||
description: 'Test, rate and improve your Node.js knowledge with these questions.'
|
||||
isNew: true
|
||||
seo:
|
||||
title: 'Node.js Questions'
|
||||
description: 'Curated list of Node.js questions to test, rate and improve your knowledge. Questions are based on real world experience and knowledge.'
|
||||
keywords:
|
||||
- 'node.js quiz'
|
||||
- 'node.js questions'
|
||||
- 'node.js interview questions'
|
||||
- 'node.js interview'
|
||||
- 'node.js test'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
questions:
|
||||
- question: What is Node.js?
|
||||
answer: Node.js is an open-source and cross-platform JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is REPL in Node.js?
|
||||
answer: |
|
||||
REPL stands for Read-Eval-Print-Loop. It is an interactive shell that allows you to execute JavaScript code and view the output immediately. It is useful for testing small snippets of code and experimenting with the Node.js API.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is the difference between Node.js and JavaScript?
|
||||
answer: Node.js is a runtime environment for JavaScript. JavaScript is a programming language used to create web applications. Node.js is a runtime environment that can execute JavaScript code outside of a web browser.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is Event Loop in Node.js?
|
||||
answer: |
|
||||
The event loop is a single-threaded loop responsible for handling all asynchronous tasks in Node.js. It continuously checks for events and executes associated callback functions, allowing Node.js to handle asynchronous tasks efficiently. Its non-blocking I/O model ensures that it can process multiple operations simultaneously without waiting for one to complete before moving on to the next, contributing to its scalability and performance. [Watch this video](https://www.youtube.com/watch?v=8aGhZQkoFbQ) to learn more about the topic.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the difference between Node.js and AJAX?
|
||||
answer: |
|
||||
Node.js is a server-side runtime for JavaScript, while AJAX is a client-side technique for asynchronous communication with the server.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What are modules in Node.js?
|
||||
answer: |
|
||||
Modules are reusable blocks of code that can be imported into other files. They are used to encapsulate related code into a single unit of code that can be used in other parts of the program. It allow us to split our code into multiple files and reuse it across multiple files. Some built-in modules include `fs`, `http`, `path`, `url`, `util`, etc.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: Difference between CommonJS and ESM?
|
||||
answer: commonjs-vs-esm.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the `global` object in Node.js?
|
||||
answer: |
|
||||
The `global` object is a global namespace object that contains all global variables, functions, and objects. It is similar to the `window` object in the browser. It can be accessed from anywhere in the program without importing it.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the difference between `process.nextTick()` and `setImmediate()`?
|
||||
answer: |
|
||||
`process.nextTick()` and `setImmediate()` are both used to schedule a callback function to be executed in the next iteration of the event loop. The difference is that `process.nextTick()` executes the callback at the end of the current iteration of the event loop, while `setImmediate()` executes the callback at the beginning of the next iteration of the event loop.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is `setInterval()`?
|
||||
answer: |
|
||||
`setInterval()` is a global function that helps you execute a function repeatedly at a fixed delay. It returns an interval ID that uniquely identifies the interval, which can be used to cancel the interval using the `clearInterval()` function.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is `setTimeout()`?
|
||||
answer: |
|
||||
`setTimeout()` is a global function that helps you execute a function after a specified delay. It returns a timeout ID that uniquely identifies the timeout, which can be used to cancel the timeout using the `clearTimeout()` function.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What are Event Emitters in Node.js?
|
||||
answer: |
|
||||
Event Emitters is a class that can be used to emit named events and register listeners for those events. It is used to handle asynchronous events in Node.js.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is `npm`?
|
||||
answer: |
|
||||
`npm` is a package manager for Node.js. It is used to install, update, and remove packages from the Node.js ecosystem. It is also used to manage dependencies for Node.js projects.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is the full form of `npm`?
|
||||
answer: |
|
||||
`npm` stands for Node Package Manager.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is `npx`?
|
||||
answer: |
|
||||
`npx` is a tool that allows you to run Node.js packages without installing them. It is used to execute Node.js packages that are not installed globally.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is `process.cwd()`?
|
||||
answer: |
|
||||
`process.cwd()` returns the current working directory of the Node.js process. It is similar to `pwd` in Unix.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the difference between `process.cwd()` and `__dirname`?
|
||||
answer: process-cwd-vs-dirname.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is `__filename`?
|
||||
answer: |
|
||||
`__filename` is a global variable that contains the absolute path of the current file.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is `process.argv`?
|
||||
answer: process-argv.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the purpose of `fs` module?
|
||||
answer: |
|
||||
The File System (fs) module is used to perform file operations such as reading, writing, and deleting files. All file system operations have synchronous and asynchronous forms.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What is the purpose of `path` module?
|
||||
answer: |
|
||||
The Path module is used to perform operations on file and directory paths. It provides methods for resolving and normalizing paths, joining paths, and extracting file and directory names.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: How to read a file in Node.js?
|
||||
answer: |
|
||||
The `fs.readFile()` method is used to read the contents of a file asynchronously. It takes the path of the file to be read and a callback function as arguments. The callback function is called with two arguments, `err` and `data`. If an error occurs while reading the file, the `err` argument will contain the error object. Otherwise, the `data` argument will contain the contents of the file.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: How to load environment variables from a `.env` file in Node.js?
|
||||
answer: |
|
||||
The `dotenv` package is used to load environment variables from a `.env` file into `process.env`. It is used to store sensitive information such as API keys, database credentials, etc. in a `.env` file instead of hardcoding them in the source code.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: How to access environment variables in Node.js?
|
||||
answer: |
|
||||
Environment variables can be accessed using the `process.env` object. It is an object that contains all the environment variables defined in the current process.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: How to take user input from the command line in Node.js?
|
||||
answer: input-from-command-line.md
|
||||
topics:
|
||||
- 'CLI'
|
||||
- 'Beginner'
|
||||
- question: How to create a web server in Node.js?
|
||||
answer: web-server.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Beginner'
|
||||
- question: What are streams in Node.js?
|
||||
answer: |
|
||||
Streams are objects that allow you to read data from a source or write data to a destination in a continuous manner. They are used to handle large amounts of data efficiently.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Advanced'
|
||||
- question: What is difference between `fork` and `spawn` methods of `child_process` module?
|
||||
answer: |
|
||||
The `fork` method is used when you want to run another JavaScript file in a separate worker. It's like having a friend with a specific task. You can communicate with them via messages and they can send messages back to you. The `spawn` method is used when you want to run a command in a separate process. It's like asking someone to do a specific. You can communicate with them via stdin/stdout/stderr, but it's more like giving orders and getting results.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Advanced'
|
||||
- question: What is the `os` module?
|
||||
answer: |
|
||||
The `os` module provides methods for interacting with the operating system. It can be used to get information about the operating system, such as the hostname, platform, architecture, etc.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: Can you access the DOM in Node.js?
|
||||
answer: |
|
||||
No, you cannot access the DOM in Node.js because it does not have a DOM. It is a server-side runtime for JavaScript, so it does not have access to the browser's DOM.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is Clustering in Node.js?
|
||||
answer: |
|
||||
Clustering is a technique used to distribute the load across multiple processes. It is used to improve the performance and scalability of Node.js applications.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Advanced'
|
||||
- question: How can memory leaks happen in Node.js?
|
||||
answer: |
|
||||
Memory leaks happen when a program allocates memory but does not release it when it is no longer needed. This can happen due to bugs in the program or due to the way the program is designed. In Node.js, memory leaks can happen due to the use of closures, circular references, and global variables.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is the order priority of `process.nextTick`, `Promise`, `setTimeout`, and `setImmediate`?
|
||||
answer: order-priority.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: What is `process.exit()`?
|
||||
answer: |
|
||||
`process.exit()` is a method that can be used to exit the current process. It takes an optional exit code as an argument. If no exit code is specified, it defaults to 0.
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: Different exit codes in Node.js?
|
||||
answer: exit-codes.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
- question: How Node.js handle errors?
|
||||
answer: error-handling.md
|
||||
topics:
|
||||
- 'Core'
|
||||
- 'Intermediate'
|
||||
---
|
||||
@@ -4,7 +4,7 @@ briefTitle: 'React'
|
||||
briefDescription: 'Test, rate and improve your React knowledge with these questions.'
|
||||
title: 'React Questions'
|
||||
description: 'Test, rate and improve your React knowledge with these questions.'
|
||||
isNew: true
|
||||
isNew: false
|
||||
seo:
|
||||
title: 'React Questions'
|
||||
description: 'Curated list of React questions to test, rate and improve your knowledge. Questions are based on real world experience and knowledge.'
|
||||
|
||||
@@ -6,7 +6,7 @@ briefDescription: 'Step by step guide to becoming an Android Developer in 2024'
|
||||
title: 'Android Developer'
|
||||
description: 'Step by step guide to becoming an Android developer in 2024'
|
||||
hasTopics: true
|
||||
isNew: true
|
||||
isNew: false
|
||||
dimensions:
|
||||
width: 968
|
||||
height: 2197.76
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# What is and how to use Gradle?
|
||||
|
||||
**Using Gradle**: Gradle is a powerful build system used in Android development that allows you to define your project and dependencies, and distinguish between different build types and flavors. Gradle uses a domain-specific language (DSL) which gives developers almost complete control over the build process. When you trigger a build in Android Studio, Gradle is the tool working behind the scenes to compile and package your app. It looks at the dependencies you declared in your build.gradle files and creates a build script accordingly. Using Gradle in android development requires continuous editing of the build.gradle files to manage app dependencies, build variants, signing configurations and other essential aspects related to building your app.
|
||||
**Using Gradle**: Gradle is a powerful build system used in Android development that allows you to define your project and dependencies, and distinguish between different build types and flavors. Gradle uses a domain-specific language (DSL) which gives developers almost complete control over the build process. When you trigger a build in Android Studio, Gradle is the tool working behind the scenes to compile and package your app. It looks at the dependencies you declared in your build.gradle files and create a build script accordingly. Using Gradle in Android development requires continuous editing of the build.gradle files to manage app dependencies, build variants, signing configurations, and other essential aspects related to building your app.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Introduction to Gradle for Complete Beginners - 25minutes](https://youtu.be/-dtcEMLNmn0?si=NuIP-3wNpUrxfTxA)
|
||||
- [Gradle Course for Beginners - 55minutes](https://www.youtube.com/watch?v=R6Z-Sxb837I)
|
||||
|
||||
|
||||
3214
src/data/roadmaps/backend/backend-beginner.json
Normal file
3214
src/data/roadmaps/backend/backend-beginner.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ tnsBannerLink: 'https://thenewstack.io?utm_source=roadmap.sh&utm_medium=Referral
|
||||
question:
|
||||
title: 'What is Backend Development?'
|
||||
description: |
|
||||
Backend web development is the part of web development that deals with the server-side of a web application. This includes creating and managing the server-side logic, connecting the application to a database, creating server-side APIs, handling user authentication and authorization, and processing and responding to user requests. It often involves the use of programming languages such as Python, Java, Ruby, PHP, JavaScript (Node.js), and .NET languages.
|
||||
Backend web development is the part of web development that deals with the server-side of a web application. This includes creating and managing the server-side logic, connecting the application to a database, creating server-side APIs, handling user authentication and authorization, and processing and responding to user requests. It often involves the use of [backend development languages](https://roadmap.sh/backend/languages) such as Python, Java, Ruby, PHP, JavaScript (Node.js), and .NET languages.
|
||||
|
||||
## What does a Backend Developer do?
|
||||
A backend developer is responsible for the development of server-side components of a web application i.e. working with databases, handling requests, creating server-side APIs that can be consumed by frontend developers to retrieve and manipulate data, ensuring the scalability of the systems i.e. making sure that the backend can handle a high volume of traffic and is performant, integrating external services like payment gateways, message queues, cloud services, etc.
|
||||
|
||||
@@ -7,7 +7,6 @@ Visit the following resources to learn more:
|
||||
- [Visit Dedicated Go Roadmap](/golang)
|
||||
- [A Tour of Go – Go Basics](https://go.dev/tour/welcome/1)
|
||||
- [Go Reference Documentation](https://go.dev/doc/)
|
||||
- [Learn Go | Boot.dev](https://boot.dev/learn/learn-golang)
|
||||
- [Go by Example - annotated example programs](https://gobyexample.com/)
|
||||
- [Learn Go | Codecademy](https://www.codecademy.com/learn/learn-go)
|
||||
- [W3Schools Go Tutorial ](https://www.w3schools.com/go/)
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
# Hateoas
|
||||
|
||||
HATEOAS is an acronym for <b>H</b>ypermedia <b>A</b>s <b>T</b>he <b>E</b>ngine <b>O</b>f <b>A</b>pplication <b>S</b>tate, it's the concept that when sending information over a RESTful API the document received should contain everything the client needs in order to parse and use the data i.e they don't have to contact any other endpoint not explicitly mentioned within the Document
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Oktane17: Designing Beautiful REST + JSON APIs (3:56 - 5:57)](https://youtu.be/MiOSzpfP1Ww?t=236)
|
||||
HATEOAS is an acronym for <b>H</b>ypermedia <b>A</b>s <b>T</b>he <b>E</b>ngine <b>O</b>f <b>A</b>pplication <b>S</b>tate, it's the concept that when sending information over a RESTful API the document received should contain everything the client needs in order to parse and use the data i.e they don't have to contact any other endpoint not explicitly mentioned within the Document.
|
||||
|
||||
@@ -8137,7 +8137,7 @@
|
||||
"x": "426",
|
||||
"y": "1521",
|
||||
"properties": {
|
||||
"controlName": "103-smart-contract-frameworks:dapp-tools"
|
||||
"controlName": "103-smart-contract-frameworks:foundry"
|
||||
},
|
||||
"children": {
|
||||
"controls": {
|
||||
|
||||
@@ -8,4 +8,3 @@ Visit the following resources to learn more:
|
||||
- [What is Cryptography](https://www.synopsys.com/glossary/what-is-cryptography.html)
|
||||
- [Asymmetric Encryption - Simply explained](https://youtu.be/AQDCe585Lnc)
|
||||
- [What is Cryptography?](https://www.youtube.com/watch?v=6_Cxj5WKpIw)
|
||||
- [Learn Cryptography](https://www.youtube.com/watch?v=trHox1bN5es)
|
||||
|
||||
@@ -7,7 +7,6 @@ Visit the following resources to learn more:
|
||||
- [Visit Dedicated Go Roadmap](/golang)
|
||||
- [A Tour of Go – Go Basics](https://go.dev/tour/welcome/1)
|
||||
- [Go Reference Documentation](https://go.dev/doc/)
|
||||
- [Learn Go | Boot.dev](https://boot.dev/learn/learn-golang)
|
||||
- [Go by Example - annotated example programs](https://gobyexample.com/)
|
||||
- [Learn Go | Codecademy](https://www.codecademy.com/learn/learn-go)
|
||||
- [W3Schools Go Tutorial ](https://www.w3schools.com/go/)
|
||||
|
||||
@@ -8,7 +8,6 @@ Visit the following resources to learn more:
|
||||
- [A Tour of Go – Go Basics](https://go.dev/tour/welcome/1)
|
||||
- [Go Reference Documentation](https://go.dev/doc/)
|
||||
- [Go by Example - annotated example programs](https://gobyexample.com/)
|
||||
- [Learn Go | Boot.dev](https://boot.dev/learn/learn-golang)
|
||||
- [Learn Go | Codecademy](https://www.codecademy.com/learn/learn-go)
|
||||
- [W3Schools Go Tutorial ](https://www.w3schools.com/go/)
|
||||
- [Making a RESTful JSON API in Go](https://thenewstack.io/make-a-restful-json-api-go/)
|
||||
|
||||
@@ -6,7 +6,7 @@ briefTitle: 'C++'
|
||||
briefDescription: 'Step by step guide to becoming a C++ Developer in 2024'
|
||||
title: 'C++ Developer Roadmap'
|
||||
description: 'Step by step guide to becoming a C++ developer in 2024'
|
||||
isNew: true
|
||||
isNew: false
|
||||
hasTopics: true
|
||||
dimensions:
|
||||
width: 1000
|
||||
|
||||
@@ -13,4 +13,4 @@ Visit the following resources to learn more:
|
||||
- [Node.js Tutorial for Beginners](https://www.youtube.com/watch?v=TlB_eWDSMt4)
|
||||
- [W3Schools – Node.js Tutorial](https://www.w3schools.com/nodejs/)
|
||||
- [What is NPM?](https://www.w3schools.com/nodejs/nodejs_npm.asp)
|
||||
- [Official Documentation](https://nodejs.dev/en/learn/)
|
||||
- [Official Documentation](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)
|
||||
|
||||
@@ -7,7 +7,6 @@ Visit the following resources to learn more:
|
||||
- [Visit Dedicated Go Roadmap](/golang)
|
||||
- [A Tour of Go – Go Basics](https://go.dev/tour/welcome/1)
|
||||
- [Go Reference Documentation](https://go.dev/doc/)
|
||||
- [Learn Go | Boot.dev](https://boot.dev/learn/learn-golang)
|
||||
- [Go by Example - annotated example programs](https://gobyexample.com/)
|
||||
- [Learn Go | Codecademy](https://www.codecademy.com/learn/learn-go)
|
||||
- [W3Schools Go Tutorial ](https://www.w3schools.com/go/)
|
||||
|
||||
@@ -8,5 +8,5 @@ Argo CD is designed to be a simple and efficient way to manage cloud-native appl
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Argo CD - Argo Project](https://argoproj.github.io/docs/argo-cd/)
|
||||
- [Argo CD - Argo Project](https://argo-cd.readthedocs.io/en/stable/)
|
||||
- [ArgoCD Tutorial for Beginners](https://www.youtube.com/watch?v=MeU5_k9ssrs)
|
||||
|
||||
@@ -7,4 +7,4 @@ Visit the following resources to learn more:
|
||||
- [Esbuild Official Website](https://esbuild.github.io/)
|
||||
- [Esbuild Documentation](https://esbuild.github.io/api/)
|
||||
- [Why are People Obsessed with esbuild?](https://www.youtube.com/watch?v=9XS_RA6zyyU)
|
||||
- [What Is ESBuild?](https://www.youtube.com/watch?v=zy8vu8cbwf0)
|
||||
- [What Is ESBuild?](https://www.youtube.com/watch?v=ZY8Vu8cbWF0)
|
||||
|
||||
@@ -5,6 +5,6 @@ Node.js is an open-source and cross-platform JavaScript runtime environment. It
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Official Website](https://nodejs.org/en/about/)
|
||||
- [Learn Node.js Official Website](https://nodejs.dev/en/learn/)
|
||||
- [Learn Node.js Official Website](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)
|
||||
- [Node.JS Introduction](https://www.w3schools.com/nodejs/nodejs_intro.asp)
|
||||
- [Node.js and Express.js Full Course](https://www.youtube.com/watch?v=Oe421EPjeBE)
|
||||
@@ -1,3 +1,7 @@
|
||||
# Quaternion
|
||||
|
||||
The **quaternion** is a complex number system that extends the concept of rotations in three dimensions. It involves four components: one real and three imaginary parts. Quaternions are used in game development for efficient and accurate calculations of rotations and orientation. They are particularly useful over other methods, such as Euler angles, due to their resistance to problems like Gimbal lock. Despite their complex nature, understanding and implementing quaternions can greatly enhance a game's 3D rotational mechanics and accuracy.
|
||||
The **quaternion** is a complex number system that extends the concept of rotations in three dimensions. It involves four components: one real and three imaginary parts. Quaternions are used in game development for efficient and accurate calculations of rotations and orientation. They are particularly useful over other methods, such as Euler angles, due to their resistance to problems like Gimbal lock. Despite their complex nature, understanding and implementing quaternions can greatly enhance a game's 3D rotational mechanics and accuracy.
|
||||
|
||||
- [Understanding Quaternions](https://www.3dgep.com/understanding-quaternions/)
|
||||
- [Unity docs - Quaternions](https://docs.unity3d.com/ScriptReference/Quaternion.html)
|
||||
- [Quaternions and 3d rotation,explained interactively](https://youtu.be/zjMuIxRvygQ?si=ANmFr5k8JMUzBCUC)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# Rust
|
||||
|
||||
**Rust** is a modern, open-source, multi-paradigm programming language designed for performance and safety, especially safe concurrency. It was initially designed by Mozilla Research as a language that can provide memory safety without garbage collection. Since then, it has gained popularity due to its features and performance that often compare favorably to languages like C++. Its rich type system and ownership model guarantee memory-safety and thread-safety while maintaining a high level of abstraction. Rust supports a mixture of imperative procedural, concurrent actor, object-oriented and pure functional styles.
|
||||
**Rust** is a modern, open-source, multi-paradigm programming language designed for performance and safety, especially safe concurrency. It was initially designed by Mozilla Research as a language that can provide memory safety without garbage collection. Since then, it has gained popularity due to its features and performance that often compare favorably to languages like C++. Its rich type system and ownership model guarantee memory-safety and thread-safety while maintaining a high level of abstraction. Rust supports a mixture of imperative procedural, concurrent actor, object-oriented and pure functional styles.
|
||||
|
||||
[Learn Rust full tutorial](https://youtu.be/BpPEoZW5IiY?si=lyBbBPLXQ0HWdJNr
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# Python
|
||||
|
||||
Python is an interpreted high-level general-purpose programming language. Its design philosophy emphasizes code readability with its significant use of indentation. Its language constructs as well as its object-oriented approach aim to help programmers write clear, logical code for small and large-scale projects. Python is dynamically-typed and garbage-collected. It supports multiple programming paradigms, including structured (particularly, procedural), object-oriented and functional programming. Python is often described as a "batteries included" language due to its comprehensive standard library.
|
||||
|
||||
To start learning Python, here are some useful resources:
|
||||
|
||||
- [Python.org](https://www.python.org/) - The official website offers extensive documentation and tutorials for beginners as well as advanced users.
|
||||
- [Codecademy's Python Course](https://www.codecademy.com/learn/learn-python) - A comprehensive, interactive course covering a wide range of Python topics.
|
||||
- [Real Python](https://realpython.com/) - Offers a variety of Python tutorials, articles, and courses that cater to different experience levels.
|
||||
- [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/) - A beginner-friendly book that teaches Python by guiding you through practical tasks and automation examples.
|
||||
|
||||
Remember, practice is key, and the more you work with Python, the more you'll appreciate its utility in the world of cyber security.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Bash
|
||||
|
||||
Understanding bash is essential for MLOps tasks.
|
||||
|
||||
- **Book Suggestion:** _The Linux Command Line, 2nd Edition_ by William E. Shotts
|
||||
- [Bash Scripting Tutorial](https://www.freecodecamp.org/news/bash-scripting-tutorial-linux-shell-script-and-command-line-for-beginners/)
|
||||
@@ -0,0 +1,3 @@
|
||||
# Programming Fundamentals
|
||||
|
||||
Programming is the key requirement for MLOps. You need to be proficient in atleast one programming language. Python is the most popular language for MLOps.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Git
|
||||
|
||||
[Git](https://git-scm.com/) is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Git & GitHub Crash Course For Beginners](https://www.youtube.com/watch?v=SWYqp7iY_Tc)
|
||||
- [Learn Git with Tutorials, News and Tips - Atlassian](https://www.atlassian.com/git)
|
||||
- [Git Cheat Sheet](https://cs.fyi/guide/git-cheatsheet)
|
||||
@@ -0,0 +1,14 @@
|
||||
# GitHub
|
||||
|
||||
GitHub is a provider of Internet hosting for software development and version control using Git. It offers the distributed version control and source code management functionality of Git, plus its own features.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [GitHub Website](https://github.com)
|
||||
- [GitHub Documentation](https://docs.github.com/en/get-started/quickstart)
|
||||
- [How to Use Git in a Professional Dev Team](https://ooloo.io/project/github-flow)
|
||||
- [What is GitHub?](https://www.youtube.com/watch?v=w3jLJU7DT5E)
|
||||
- [Git vs. GitHub: Whats the difference?](https://www.youtube.com/watch?v=wpISo9TNjfU)
|
||||
- [Git and GitHub for Beginners](https://www.youtube.com/watch?v=RGOj5yH7evk)
|
||||
- [Git and GitHub - CS50 Beyond 2019](https://www.youtube.com/watch?v=eulnSXkhE7I)
|
||||
- [Learn Git Branching](https://learngitbranching.js.org/?locale=en_us)
|
||||
@@ -0,0 +1,8 @@
|
||||
# Version Control Systems
|
||||
|
||||
Version control/source control systems allow developers to track and control changes to code over time. These services often include the ability to make atomic revisions to code, branch/fork off of specific points, and to compare versions of code. They are useful in determining the who, what, when, and why code changes were made.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Git](https://git-scm.com/)
|
||||
- [What is Version Control?](https://www.atlassian.com/git/tutorials/what-is-version-control)
|
||||
@@ -0,0 +1,9 @@
|
||||
# AWS / Azure / GCP
|
||||
|
||||
AWS (Amazon Web Services) Azure and GCP (Google Cloud Platform) are three leading providers of cloud computing services. AWS by Amazon is the oldest and the most established among the three, providing a breadth and depth of solutions ranging from infrastructure services like compute, storage, and databases to the machine and deep learning. Azure, by Microsoft, has integrated tools for DevOps, supports a large number of programming languages, and offers seamless integration with on-prem servers and Microsoft’s software. Google's GCP has strength in cost-effectiveness, live migration of virtual machines, and flexible computing options. All three have introduced various MLOps tools and services to boost capabilities for machine learning development and operations.
|
||||
|
||||
Visit the following resources to learn more about AWS, Azure, and GCP:
|
||||
|
||||
- [AWS Roadmap](https://roadmap.sh/aws)
|
||||
- [Azure Tutorials](https://docs.microsoft.com/en-us/learn/azure/)
|
||||
- [GCP Learning Resources](https://cloud.google.com/training)
|
||||
@@ -0,0 +1,9 @@
|
||||
# Cloud-native ML Services
|
||||
|
||||
Most of the cloud providers offer managed services for machine learning. These services are designed to help data scientists and machine learning engineers to build, train, and deploy machine learning models at scale. These services are designed to be cloud-native, meaning they are designed to work with other cloud services and are optimized for the cloud environment.
|
||||
|
||||
Here are the services offered by the major cloud providers:
|
||||
|
||||
- **Amazon Web Services (AWS)**: SageMaker
|
||||
- **Google Cloud Platform (GCP)**: AI Platform
|
||||
- **Microsoft Azure**: Azure Machine Learning
|
||||
@@ -0,0 +1,3 @@
|
||||
# Cloud Computing
|
||||
|
||||
**Cloud Computing** refers to the delivery of computing services over the internet rather than using local servers or personal devices. These services include servers, storage, databases, networking, software, analytics, and intelligence. Cloud Computing enables faster innovation, flexible resources, and economies of scale. There are various types of cloud computing such as public clouds, private clouds, and hybrids clouds. Furthermore, it's divided into different services like Infrastructure as a Service (IaaS), Platform as a Service (PaaS), and Software as a Service (SaaS). These services differ mainly in the level of control an organization has over their data and infrastructures.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Docker
|
||||
|
||||
Docker is a platform for working with containerized applications. Among its features are a daemon and client for managing and interacting with containers, registries for storing images, and a desktop application to package all these features together.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Docker Documentation](https://docs.docker.com/)
|
||||
- [Docker Tutorial](https://www.youtube.com/watch?v=RqTEHSBrYFw)
|
||||
- [Docker simplified in 55 seconds](https://youtu.be/vP_4DlOH1G4)
|
||||
@@ -0,0 +1,13 @@
|
||||
# Kubernetes
|
||||
|
||||
Kubernetes is an [open source](https://github.com/kubernetes/kubernetes) container management platform, and the dominant product in this space. Using Kubernetes, teams can deploy images across multiple underlying hosts, defining their desired availability, deployment logic, and scaling logic in YAML. Kubernetes evolved from Borg, an internal Google platform used to provision and allocate compute resources (similar to the Autopilot and Aquaman systems of Microsoft Azure).
|
||||
|
||||
The popularity of Kubernetes has made it an increasingly important skill for the DevOps Engineer and has triggered the creation of Platform teams across the industry. These Platform engineering teams often exist with the sole purpose of making Kubernetes approachable and usable for their product development colleagues.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Kubernetes Website](https://kubernetes.io/)
|
||||
- [Kubernetes Documentation](https://kubernetes.io/docs/home/)
|
||||
- [Kubernetes Crash Course for Absolute Beginners](https://www.youtube.com/watch?v=s_o8dwzRlu4)
|
||||
- [Primer: How Kubernetes Came to Be, What It Is, and Why You Should Care](https://thenewstack.io/primer-how-kubernetes-came-to-be-what-it-is-and-why-you-should-care/)
|
||||
- [Kubernetes: An Overview](https://thenewstack.io/kubernetes-an-overview/)
|
||||
@@ -0,0 +1,12 @@
|
||||
# Containers
|
||||
|
||||
Containers are a construct in which [cgroups](https://en.wikipedia.org/wiki/Cgroups), [namespaces](https://en.wikipedia.org/wiki/Linux_namespaces), and [chroot](https://en.wikipedia.org/wiki/Chroot) are used to fully encapsulate and isolate a process. This encapsulated process, called a container image, shares the kernel of the host with other containers, allowing containers to be significantly smaller and faster than virtual machines.
|
||||
|
||||
These images are designed for portability, allowing for full local testing of a static image, and easy deployment to a container management platform.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [What are Containers?](https://cloud.google.com/learn/what-are-containers)
|
||||
- [What is a Container?](https://www.docker.com/resources/what-container/)
|
||||
- [What are Containers?](https://www.youtube.com/playlist?list=PLawsLZMfND4nz-WDBZIj8-nbzGFD4S9oz)
|
||||
- [Articles about Containers - The New Stack](https://thenewstack.io/category/containers/)
|
||||
6
src/data/roadmaps/mlops/content/104-ml-fundamentals.md
Normal file
6
src/data/roadmaps/mlops/content/104-ml-fundamentals.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Machine Learning Fundamentals
|
||||
|
||||
An MLOps engineer should have a basic understanding of machine learning models.
|
||||
|
||||
- **Courses:** [MLCourse.ai](https://mlcourse.ai/), [Fast.ai](https://course.fast.ai)
|
||||
- **Book Suggestion:** _Applied Machine Learning and AI for Engineers_ by Jeff Prosise
|
||||
@@ -0,0 +1,3 @@
|
||||
# Data Pipelines
|
||||
|
||||
Data pipelines refer to a set of processes that involve moving data from one system to another, for purposes such as data integration, data migration, data transformation, or data synchronization. These processes can involve a variety of data sources and destinations, and may often require data to be cleaned, enriched, or otherwise transformed along the way. It's a key concept in data engineering to ensure that data is appropriately processed from its source to the location where it will be used, typically a data warehouse, data mart, or a data lake. As such, data pipelines play a crucial part in building an effective and efficient data analytics setup, enabling the flow of data to be processed for insights.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Data lakes & Warehouses
|
||||
|
||||
"**Data Lakes** are large-scale data repository systems that store raw, untransformed data, in various formats, from multiple sources. They're often used for big data and real-time analytics requirements. Data lakes preserve the original data format and schema which can be modified as necessary. On the other hand, **Data Warehouses** are data storage systems which are designed for analyzing, reporting and integrating with transactional systems. The data in a warehouse is clean, consistent, and often transformed to meet wide-range of business requirements. Hence, data warehouses provide structured data but require more processing and management compared to data lakes."
|
||||
@@ -0,0 +1,3 @@
|
||||
# Spark / Airflow / Kafka
|
||||
|
||||
Apache Spark is an open-source distributed computing system used for big data processing and analytics. It provides an interface for programming entire clusters with implicit data parallelism and fault tolerance. On the other hand, Apache Airflow is an open-source platform to programmatically author, schedule and monitor workflows. The primary use case of Airflow is to define workflows of tasks that run at specific times or in response to specific events. Apache Kafka is a distributed event streaming platform that lets you publish, subscribe to, store, and process streams of records in real time. It is often used in situations where JMS (Java Messaging Service), RabbitMQ, and other messaging systems are found to be necessary but not powerful or flexible enough.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Data Engineering Fundamentals
|
||||
|
||||
Data Engineering is essentially dealing with the collection, validation, storage, transformation, and processing of data. The objective is to provide reliable, efficient, and scalable data pipelines and infrastructure that allow data scientists to convert data into actionable insights. It involves steps like data ingestion, data storage, data processing, and data provisioning. Important concepts include designing, building, and maintaining data architecture, databases, processing systems, and large-scale processing systems. It is crucial to have extensive technical knowledge in various tools and programming languages like SQL, Python, Hadoop, and more.
|
||||
9
src/data/roadmaps/mlops/content/106-mlops-principles.md
Normal file
9
src/data/roadmaps/mlops/content/106-mlops-principles.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# MLOps Principles
|
||||
|
||||
Awareness of MLOps principles and maturity factors is required.
|
||||
|
||||
- **Books:**
|
||||
- _Designing Machine Learning Systems_ by Chip Huyen
|
||||
- _Introducing MLOps_ by Mark Treveil and Dataiku
|
||||
- **Assessment:** [MLOps maturity assessment](https://marvelousmlops.substack.com/p/mlops-maturity-assessment)
|
||||
- **Great resource on MLOps:** [ml-ops.org](https://ml-ops.org)
|
||||
@@ -0,0 +1,8 @@
|
||||
# Version Control Systems
|
||||
|
||||
Version control/source control systems allow developers to track and control changes to code over time. These services often include the ability to make atomic revisions to code, branch/fork off of specific points, and to compare versions of code. They are useful in determining the who, what, when, and why code changes were made.
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Git](https://git-scm.com/)
|
||||
- [What is Version Control?](https://www.atlassian.com/git/tutorials/what-is-version-control)
|
||||
@@ -0,0 +1,9 @@
|
||||
# CI / CD
|
||||
|
||||
Critical for traceable and reproducible ML model deployments.
|
||||
|
||||
- **Books:**
|
||||
- _Learning GitHub Actions_ by Brent Laster
|
||||
- _Learning Git_ by Anna Skoulikari
|
||||
- **Tutorials & Courses:** [Git & GitHub for beginners](https://www.youtube.com/watch?v=RGOj5yH7evk), [Python to Production guide](https://www.udemy.com/course/setting-up-the-linux-terminal-for-software-development/), [Version Control Missing Semester](https://missing.csail.mit.edu/2020/version-control/), https://learngitbranching.js.org/
|
||||
- **Tool:** [Pre-commit hooks](https://marvelousmlops.substack.com/p/welcome-to-pre-commit-heaven)
|
||||
@@ -0,0 +1,4 @@
|
||||
Systems like Airflow and Mage are important in ML engineering.
|
||||
|
||||
- **Course:** [Introduction to Airflow in Python](https://app.datacamp.com/learn/courses/introduction-to-airflow-in-python)
|
||||
- **Note:** Airflow is also featured in the _ML Engineering with Python_ book and [_The Full Stack 7-Steps MLOps Framework_](https://www.pauliusztin.me/courses/the-full-stack-7-steps-mlops-framework).
|
||||
@@ -0,0 +1,8 @@
|
||||
# Experiment Tracking and Model Registry
|
||||
|
||||
**Experiment Tracking** is an essential part of MLOps, providing a system to monitor and record the different experiments conducted during the machine learning model development process. This involves capturing, organizing and visualizing the metadata associated with each experiment, such as hyperparameters used, models produced, metrics like accuracy or loss, and other information about the computational environment. This tracking allows for reproducibility of experiments, comparison across different experiment runs, and helps in identifying the best models.
|
||||
|
||||
Logging metadata, parameters, and artifacts of training runs.
|
||||
|
||||
- **Tool:** MLflow
|
||||
- **Courses:** [MLflow Udemy course](https://www.udemy.com/course/mlflow-course/), [End-to-end machine learning (MLflow piece)](https://www.udemy.com/course/sustainable-and-scalable-machine-learning-project-development/)
|
||||
@@ -0,0 +1,9 @@
|
||||
# Data Lineage and Feature Stores
|
||||
|
||||
**Data Lineage** refers to the life-cycle of data, including its origins, movements, characteristics and quality. It's a critical component in MLOps for tracking the journey of data through every process in a pipeline, from raw input to model output. Data lineage helps in maintaining transparency, ensuring compliance, and facilitating data debugging or tracing data related bugs. It provides a clear representation of data sources, transformations, and dependencies thereby aiding in audits, governance, or reproduction of machine learning models.
|
||||
|
||||
Feature stores are a crucial component of MLOps infrastructure.
|
||||
|
||||
- **Tutorial:** Creating a feature store with Feast [Part 1](https://kedion.medium.com/creating-a-feature-store-with-feast-part-1-37c380223e2f) [Part 2](https://kedion.medium.com/feature-storage-for-ml-with-feast-part-2-34df1971a8d3) [Part 3](https://kedion.medium.com/feature-storage-for-ml-with-feast-a061899fc4a2)
|
||||
- **Tool:** DVC for data tracking
|
||||
- **Course:** [End-to-end machine learning (DVC piece)](https://www.udemy.com/course/sustainable-and-scalable-machine-learning-project-development/)
|
||||
@@ -0,0 +1,8 @@
|
||||
# Model Training and Serving
|
||||
|
||||
"Model Training" refers to the phase in the Machine Learning (ML) pipeline where we teach a machine learning model how to make predictions by providing it with data. This process begins with feeding the model a training dataset, which it uses to learn and understand patterns or perform computations. The model's performance is then evaluated by comparing its prediction outputs with the actual results. Various algorithms can be used in the model training process. The choice of algorithm usually depends on the task, the data available, and the requirements of the project. It is worth noting that the model training stage can be computationally expensive particularly when dealing with large datasets or complex models.
|
||||
|
||||
Decisions depend on the organization's infrastructure.
|
||||
|
||||
- **Repository Suggestion:** [ML Deployment k8s Fast API](https://github.com/sayakpaul/ml-deployment-k8s-fastapi/tree/main)
|
||||
- **Tutorial Suggestions:** [ML deployment with k8s FastAPI, Building an ML app with FastAPI](https://dev.to/bravinsimiyu/beginner-guide-on-how-to-build-a-machine-learning-app-with-fastapi-part-ii-deploying-the-fastapi-application-to-kubernetes-4j6g), [Basic Kubeflow pipeline](https://towardsdatascience.com/tutorial-basic-kubeflow-pipeline-from-scratch-5f0350dc1905), [Building and deploying ML pipelines](https://www.datacamp.com/tutorial/kubeflow-tutorial-building-and-deploying-machine-learning-pipelines?utm_source=google&utm_medium=paid_search&utm_campaignid=19589720818&utm_adgroupid=157156373991&utm_device=c&utm_keyword=&utm_matchtype=&utm_network=g&utm_adpostion=&utm_creative=683184494153&utm_targetid=dsa-2218886984380&utm_loc_interest_ms=&utm_loc_physical_ms=9064564&utm_content=&utm_campaign=230119_1-sea~dsa~tofu_2-b2c_3-eu_4-prc_5-na_6-na_7-le_8-pdsh-go_9-na_10-na_11-na-dec23&gad_source=1&gclid=Cj0KCQiA4Y-sBhC6ARIsAGXF1g7iSih9h2RGL27LwWY6dlPLhEss-e5Af8pnaBvdDynRh7IHIKi8sGgaApD-EALw_wcB), [KServe tutorial](https://towardsdatascience.com/kserve-highly-scalable-machine-learning-deployment-with-kubernetes-aa7af0b71202)
|
||||
@@ -0,0 +1,7 @@
|
||||
# Monitoring and Observability
|
||||
|
||||
**Monitoring** in MLOps primarily involves tracking the performance of machine learning (ML) models in production to ensure that they continually deliver accurate and reliable results. Such monitoring is necessary because the real-world data that these models handle may change over time, a scenario known as data drift. These changes can adversely affect model performance. Monitoring helps to detect any anomalies in the model’s behaviour or performance and such alerts can trigger the retraining of models with new data. From a broader perspective, monitoring also involves tracking resources and workflows to detect and rectify any operational issues in the MLOps pipeline.
|
||||
|
||||
- [**ML Monitoring vs Observability article**](https://marvelousmlops.substack.com/p/ml-monitoring-vs-ml-observability)
|
||||
- **Course:** [Machine learning monitoring concepts](https://app.datacamp.com/learn/courses/machine-learning-monitoring-concepts), [Monitoring ML in Python](https://app.datacamp.com/learn/courses/monitoring-machine-learning-in-python)
|
||||
- **Tools:** [Prometheus, Grafana](https://www.udemy.com/course/mastering-prometheus-and-grafana/)
|
||||
@@ -0,0 +1,3 @@
|
||||
# MLOps Components
|
||||
|
||||
MLOps components can be broadly classified into three major categories: Development, Operations and Governance. The **Development** components include everything involved in the creation of machine learning models, such as data extraction, data analysis, feature engineering, and machine learning model training. The **Operations** category includes components involved in deploying, monitoring, and maintaining machine learning models in production. This may include release management, model serving, and performance monitoring. Lastly, the **Governance** category encompasses the policies and regulations related to machine learning models. This includes model audit and tracking, model explainability, and security & compliance regulations.
|
||||
7
src/data/roadmaps/mlops/content/108-infra-as-code.md
Normal file
7
src/data/roadmaps/mlops/content/108-infra-as-code.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Infrastructure as Code
|
||||
|
||||
Essential for a reproducible MLOps framework.
|
||||
|
||||
- **Course:** [Terraform course for beginners](https://www.youtube.com/watch?v=SLB_c_ayRMo)
|
||||
- **Video:** [8 Terraform best practices by Techworld by Nana](https://www.youtube.com/watch?v=gxPykhPxRW0)
|
||||
- **Book Suggestion:** _Terraform: Up and Running, 3rd Edition_ by Yevgeniy Brikman
|
||||
1
src/data/roadmaps/mlops/content/index.md
Normal file
1
src/data/roadmaps/mlops/content/index.md
Normal file
@@ -0,0 +1 @@
|
||||
#
|
||||
0
src/data/roadmaps/mlops/faqs.astro
Normal file
0
src/data/roadmaps/mlops/faqs.astro
Normal file
2893
src/data/roadmaps/mlops/mlops.json
Normal file
2893
src/data/roadmaps/mlops/mlops.json
Normal file
File diff suppressed because it is too large
Load Diff
38
src/data/roadmaps/mlops/mlops.md
Normal file
38
src/data/roadmaps/mlops/mlops.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
jsonUrl: '/jsons/roadmaps/mlops.json'
|
||||
pdfUrl: '/pdfs/roadmaps/mlops.pdf'
|
||||
order: 18
|
||||
briefTitle: 'MLOps'
|
||||
briefDescription: 'Step by step guide to learn MLOps in 2024'
|
||||
title: 'MLOps Roadmap'
|
||||
description: 'Step by step guide to learn MLOps in 2024'
|
||||
hasTopics: true
|
||||
isNew: true
|
||||
dimensions:
|
||||
width: 968
|
||||
height: 1256.63
|
||||
schema:
|
||||
headline: 'MLOps Roadmap'
|
||||
description: 'Learn about MLOps with this interactive step by step guide in 2023. We also have resources and short descriptions attached to the roadmap items so you can get everything you want to learn in one place.'
|
||||
imageUrl: 'https://roadmap.sh/roadmaps/mlops.png'
|
||||
datePublished: '2024-02-12'
|
||||
dateModified: '2024-02-12'
|
||||
seo:
|
||||
title: 'MLOps Roadmap'
|
||||
description: 'Learn about MLOps using this roadmap. Community driven, articles, resources, guides, interview questions, quizzes for modern backend development.'
|
||||
keywords:
|
||||
- 'mlops roadmap 2024'
|
||||
- 'mlops engineer'
|
||||
- 'machine learning engineer'
|
||||
- 'ai ops engineer'
|
||||
relatedRoadmaps:
|
||||
- 'ai-data-scientist'
|
||||
- 'python'
|
||||
sitemap:
|
||||
priority: 1
|
||||
changefreq: 'monthly'
|
||||
tags:
|
||||
- 'roadmap'
|
||||
- 'main-sitemap'
|
||||
- 'role-roadmap'
|
||||
---
|
||||
@@ -70,4 +70,4 @@ db.events.aggregate([
|
||||
|
||||
This query groups events by the day and year, providing a count of events for each day.
|
||||
|
||||
- [MongoDB Documentation Date](https://www.mongodb.com/docs/manual/reference/method/date/)
|
||||
- [MongoDB Documentation Date](https://www.mongodb.com/docs/manual/reference/method/Date/)
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
# Analyzer
|
||||
# MongoDB Analyzer
|
||||
|
||||
The Visual Studio (VS) Analyzer for MongoDB is a powerful development tool that helps you work with MongoDB by providing an integrated environment within your Visual Studio IDE. This add-on enhances your productivity and efficiency when developing applications with MongoDB, as it offers several benefits such as code assistance, syntax highlighting, IntelliSense support, and more.
|
||||
The MongoDB Analyzer for Visual Studio (VS) is a powerful development tool that helps you work with MongoDB by providing an integrated environment within your Visual Studio IDE. This add-on enhances your productivity and efficiency when developing applications with MongoDB, as it offers several benefits such as code assistance, syntax highlighting, IntelliSense support, and more.
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Syntax Highlighting**: The VS Analyzer provides syntax highlighting to help you quickly identify and understand different elements in your code, such as variables, operators, and functions.
|
||||
- **Syntax Highlighting**: The MongoDB Analyzer provides syntax highlighting to help you quickly identify and understand different elements in your code, such as variables, operators, and functions.
|
||||
|
||||
- **IntelliSense Support**: IntelliSense is an intelligent code completion feature that predicts and suggests likely entries based on the context. It makes it easier to write queries by providing contextual suggestions based on your input.
|
||||
|
||||
- **Code Snippets**: This feature allows you to insert common MongoDB code patterns and functionalities directly into your code editor with just a few clicks. This can save you time and help maintain a consistent coding style across your project.
|
||||
|
||||
- **Query Profiling**: The VS Analyzer allows you to profile and optimize MongoDB queries. By analyzing query performance, you can identify slow or problematic queries and make appropriate improvements to ensure better performance.
|
||||
- **Query Profiling**: The MongoDB Analyzer allows you to profile and optimize MongoDB queries. By analyzing query performance, you can identify slow or problematic queries and make appropriate improvements to ensure better performance.
|
||||
|
||||
- **Debugging**: The Analyzer offers debugging support to help you identify and fix issues in your MongoDB queries and scripts, improving the overall reliability of your application.
|
||||
|
||||
- **Integrated Shell**: VS Analyzer offers an integrated shell within Visual Studio that allows you to run MongoDB commands and queries directly within the IDE. This makes it more convenient to interact with your MongoDB instances and perform various tasks without switching between different tools.
|
||||
- **Integrated Shell**: MongoDB Analyzer offers an integrated shell within Visual Studio that allows you to run MongoDB commands and queries directly within the IDE. This makes it more convenient to interact with your MongoDB instances and perform various tasks without switching between different tools.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To start using the VS Analyzer for MongoDB, follow these steps:
|
||||
|
||||
- Download and install the [Visual Studio MongoDB Extension](https://marketplace.visualstudio.com/items?itemName=ms-ossdata.vscode-mongodb) from the Visual Studio Marketplace.
|
||||
To start using MongoDB Analyzer for Visual Studio, follow these steps:
|
||||
|
||||
- Open your Visual Studio IDE and create a new project or open an existing one.
|
||||
|
||||
- Add a reference to the MongoDB extension in your project by right-clicking on `References` and selecting `Add Package`.
|
||||
- Download and install the [MongoDB Analyzer as a NuGet package](https://www.nuget.org/packages/MongoDB.Analyzer/1.0.0) in Visual Studio from:
|
||||
|
||||
- Search for `MongoDB` in the package manager window, and install the relevant packages for your project.
|
||||
- **Package Manager**: Click `Tools` > `NuGet Package Manager` > `Package Manager Console` and then execute this command: ```Install-Package MongoDB.Analyzer -Version 1.0.0```
|
||||
- **.NET CLI**: Click `View` > `Terminal` and then execute this command: ```dotnet add package MongoDB.Analyzer --version 1.0.0```
|
||||
|
||||
- Once the extension is installed, you can access the MongoDB features through the `Extensions` menu in Visual Studio.
|
||||
- Once installed, it will be added to your project’s Dependencies list, under Analyzers.
|
||||
|
||||
With the VS Analyzer for MongoDB, you'll be able to write cleaner, faster, and more efficient code, making it an essential tool for any MongoDB developer.
|
||||
- After installing and once the analyzer has run, you’ll find all of the diagnostic warnings output to the Error List panel. As you start to inspect your code, you’ll also see that any unsupported expressions will be highlighted.
|
||||
|
||||
- Learn more about MongoDB Analyzer from the [official docs](https://www.mongodb.com/developer/languages/csharp/introducing-mongodb-analyzer-dotnet/).
|
||||
|
||||
With the MongoDB Analyzer for Visual Studio, you'll be able to write cleaner, faster, and more efficient code, making it an essential tool for any MongoDB developer.
|
||||
|
||||
@@ -6,6 +6,6 @@ Visit the following resources to learn more:
|
||||
|
||||
- [Official Website](https://nodejs.org/en/about/)
|
||||
- [Node.JS Introduction](https://www.w3schools.com/nodejs/nodejs_intro.asp)
|
||||
- [Official Website](https://nodejs.dev/en/learn/)
|
||||
- [Official Website](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)
|
||||
- [What is Node.js?](https://www.youtube.com/watch?v=uVwtVBpw7RQ)
|
||||
- [How Node.js Works?](https://www.youtube.com/watch?v=jOupHNvDIq8)
|
||||
|
||||
@@ -5,6 +5,6 @@ Node.js is a cross-platform runtime, perfect for a wide range of use cases. Its
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [Pros of Node.js](https://www.freecodecamp.org/news/what-are-the-advantages-of-node-js/)
|
||||
- [Learn Node.js](https://nodejs.dev/en/learn/)
|
||||
- [Learn Node.js](https://nodejs.org/en/learn/getting-started/introduction-to-nodejs)
|
||||
- [Why Choose Node.js?](https://medium.com/selleo/why-choose-node-js-b0091ad6c3fc)
|
||||
- [5 Reasons to Choose Node.js](https://www.bitovi.com/blog/5-reasons-to-choose-nodejs)
|
||||
|
||||
@@ -8,4 +8,5 @@ Visit the following resources to learn more:
|
||||
- [JavaScript Visualized: Event Loop](https://dev.to/lydiahallie/javascript-visualized-event-loop-3dif)
|
||||
- [The Node.js Event Loop](https://www.coursera.org/lecture/secure-full-stack-mean-developer/the-node-js-event-loop-j5fbT)
|
||||
- [The Complete Node js: The Node js Event Loop](https://www.youtube.com/watch?v=6YgsqXlUoTM)
|
||||
- [The NodeJS Event loop](https://nodejs.dev/en/learn/the-nodejs-event-loop/)
|
||||
- [The NodeJS Event loop](https://nodejs.org/en/guides/event-loop-timers-and-nexttick)
|
||||
- [Don't Block the Event Loop](https://nodejs.org/en/guides/dont-block-the-event-loop)
|
||||
|
||||
@@ -4,5 +4,5 @@ In Node.js, an event can be described simply as a string with a corresponding ca
|
||||
|
||||
Visit the following resources to learn more:
|
||||
|
||||
- [What are Event Emitters?](https://nodejs.dev/en/learn/the-nodejs-event-emitter/)
|
||||
- [What are Event Emitters?](https://nodejs.org/en/learn/asynchronous-work/the-nodejs-event-emitter)
|
||||
- [Using Event Emitters in Node.js](https://www.digitalocean.com/community/tutorials/using-event-emitters-in-node-js)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user