Juiced up rtk template
This commit is contained in:
28
README.md
28
README.md
@@ -1,27 +1 @@
|
||||
# vite-template-redux
|
||||
|
||||
Uses [Vite](https://vitejs.dev/), [Vitest](https://vitest.dev/), and [React Testing Library](https://github.com/testing-library/react-testing-library) to create a modern [React](https://react.dev/) app compatible with [Create React App](https://create-react-app.dev/)
|
||||
|
||||
```sh
|
||||
npx degit reduxjs/redux-templates/packages/vite-template-redux my-app
|
||||
```
|
||||
|
||||
## Goals
|
||||
|
||||
- Easy migration from Create React App or Vite
|
||||
- As beginner friendly as Create React App
|
||||
- Optimized performance compared to Create React App
|
||||
- Customizable without ejecting
|
||||
|
||||
## Scripts
|
||||
|
||||
- `dev`/`start` - start dev server and open browser
|
||||
- `build` - build for production
|
||||
- `preview` - locally preview production build
|
||||
- `test` - launch test runner
|
||||
|
||||
## Inspiration
|
||||
|
||||
- [Create React App](https://github.com/facebook/create-react-app/tree/main/packages/cra-template)
|
||||
- [Vite](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react)
|
||||
- [Vitest](https://github.com/vitest-dev/vitest/tree/main/examples/react-testing-lib)
|
||||
# Armco Template for the tech stack: React, TS, Dart Sass, Redux Tookkit, react-redux, react browser routing, TS based plop generator
|
||||
27
package.json
27
package.json
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "vite-template-redux",
|
||||
"name": "@armco/react-vite-rtk-template",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
@@ -8,6 +8,10 @@
|
||||
"start": "vite",
|
||||
"build": "tsc && vite build",
|
||||
"generate": "plop",
|
||||
"atom": "plop atom",
|
||||
"molecule": "plop molecule",
|
||||
"component": "plop component",
|
||||
"page": "plop page",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest",
|
||||
"format": "prettier --write .",
|
||||
@@ -20,7 +24,8 @@
|
||||
"react-app-polyfill": "^3.0.0",
|
||||
"react-dev-utils": "^12.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-redux": "^8.0.1"
|
||||
"react-redux": "^8.0.1",
|
||||
"react-router-dom": "^6.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/dom": "^9.2.0",
|
||||
@@ -55,5 +60,21 @@
|
||||
"react/jsx-no-target-blank": "off"
|
||||
}
|
||||
},
|
||||
"prettier": "prettier-config-nick"
|
||||
"prettier": "prettier-config-nick",
|
||||
"main": "index.tsx",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ReStruct-Corporate-Advantage/.git"
|
||||
},
|
||||
"keywords": [
|
||||
"components",
|
||||
"atomic",
|
||||
"building-blocks",
|
||||
"foundation"
|
||||
],
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ReStruct-Corporate-Advantage/react-vite-rtk-template/issues"
|
||||
},
|
||||
"homepage": "https://github.com/ReStruct-Corporate-Advantage/react-vite-rtk-template#readme"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}";
|
||||
import React from "react"
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}"
|
||||
|
||||
describe("{{pascalCase name}}", () => {
|
||||
it("renders without error", () => {
|
||||
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -1,17 +1,14 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import "./{{pascalCase name}}.component.scss";
|
||||
import React from "react"
|
||||
import "./{{pascalCase name}}.component.scss"
|
||||
|
||||
interface {{pascalCase name}}Props {}
|
||||
|
||||
const {{pascalCase name}} = props => {
|
||||
return (
|
||||
<div className="c-{{pascalCase name}}">
|
||||
In Component {{pascalCase name}}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
{{pascalCase name}}.propTypes = {
|
||||
|
||||
};
|
||||
|
||||
export default {{pascalCase name}};
|
||||
export default {{pascalCase name}}
|
||||
@@ -1,3 +1,3 @@
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}.jsx";
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}.jsx"
|
||||
|
||||
export default {{pascalCase name}};
|
||||
export default {{pascalCase name}}
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from "react";
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}";
|
||||
import React from "react"
|
||||
import {{pascalCase name}} from "./{{pascalCase name}}"
|
||||
|
||||
describe("{{pascalCase name}}", () => {
|
||||
it("renders without error", () => {
|
||||
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
@@ -1,17 +1,14 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import "./{{pascalCase name}}.module.scss";
|
||||
import React from "react"
|
||||
import "./{{pascalCase name}}.module.scss"
|
||||
|
||||
interface {{pascalCase name}}Props {}
|
||||
|
||||
const {{pascalCase name}} = props => {
|
||||
return (
|
||||
<div className="c-{{pascalCase name}}">
|
||||
In Page {{pascalCase name}}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
{{pascalCase name}}.propTypes = {
|
||||
|
||||
};
|
||||
|
||||
export default {{pascalCase name}};
|
||||
export default {{pascalCase name}}
|
||||
100
plopfile.cjs
100
plopfile.cjs
@@ -49,6 +49,106 @@ module.exports = (plop) => {
|
||||
},
|
||||
],
|
||||
})
|
||||
plop.setGenerator("atom", {
|
||||
description: "Create a component",
|
||||
prompts: [
|
||||
{
|
||||
type: "input",
|
||||
name: "name",
|
||||
message: "What is your component name?",
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/atoms/{{pascalCase name}}/{{pascalCase name}}.tsx",
|
||||
templateFile: "plop-templates/Component/Component.tsx.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/atoms/{{pascalCase name}}/{{pascalCase name}}.test.ts",
|
||||
templateFile: "plop-templates/Component/Component.test.ts.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/atoms/{{pascalCase name}}/{{pascalCase name}}.component.scss",
|
||||
templateFile: "plop-templates/Component/Component.component.scss.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/atoms/{{pascalCase name}}/index.ts",
|
||||
templateFile: "plop-templates/Component/index.ts.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/index.ts",
|
||||
templateFile: "plop-templates/injectable-index.ts.hbs",
|
||||
skipIfExists: true,
|
||||
},
|
||||
{
|
||||
type: "append",
|
||||
path: "src/app/components/index.ts",
|
||||
pattern: `/* PLOP_INJECT_IMPORT */`,
|
||||
template: `import {{pascalCase name}} from "./atoms/{{pascalCase name}}"`,
|
||||
},
|
||||
{
|
||||
type: "append",
|
||||
path: "src/app/components/index.ts",
|
||||
pattern: `/* PLOP_INJECT_EXPORT */`,
|
||||
template: `\t{{pascalCase name}},`,
|
||||
},
|
||||
],
|
||||
})
|
||||
plop.setGenerator("molecule", {
|
||||
description: "Create a rich component",
|
||||
prompts: [
|
||||
{
|
||||
type: "input",
|
||||
name: "name",
|
||||
message: "What is your component name?",
|
||||
},
|
||||
],
|
||||
actions: [
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/molecules/{{pascalCase name}}/{{pascalCase name}}.tsx",
|
||||
templateFile: "plop-templates/Component/Component.tsx.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/molecules/{{pascalCase name}}/{{pascalCase name}}.test.ts",
|
||||
templateFile: "plop-templates/Component/Component.test.ts.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/molecules/{{pascalCase name}}/{{pascalCase name}}.component.scss",
|
||||
templateFile: "plop-templates/Component/Component.component.scss.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/molecules/{{pascalCase name}}/index.ts",
|
||||
templateFile: "plop-templates/Component/index.ts.hbs",
|
||||
},
|
||||
{
|
||||
type: "add",
|
||||
path: "src/app/components/index.ts",
|
||||
templateFile: "plop-templates/injectable-index.ts.hbs",
|
||||
skipIfExists: true,
|
||||
},
|
||||
{
|
||||
type: "append",
|
||||
path: "src/app/components/index.ts",
|
||||
pattern: `/* PLOP_INJECT_IMPORT */`,
|
||||
template: `import {{pascalCase name}} from "./molecules/{{pascalCase name}}"`,
|
||||
},
|
||||
{
|
||||
type: "append",
|
||||
path: "src/app/components/index.ts",
|
||||
pattern: `/* PLOP_INJECT_EXPORT */`,
|
||||
template: `\t{{pascalCase name}},`,
|
||||
},
|
||||
],
|
||||
})
|
||||
plop.setGenerator("page", {
|
||||
description: "Create a page",
|
||||
prompts: [
|
||||
|
||||
38
src/App.css
38
src/App.css
@@ -1,38 +0,0 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { render } from "@testing-library/react"
|
||||
import { Provider } from "react-redux"
|
||||
import { store } from "./app/store"
|
||||
import App from "./App"
|
||||
|
||||
test("renders learn react link", () => {
|
||||
const { getByText } = render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
)
|
||||
|
||||
expect(getByText(/learn/i)).toBeInTheDocument()
|
||||
})
|
||||
55
src/App.tsx
55
src/App.tsx
@@ -1,55 +0,0 @@
|
||||
import { Counter } from "./features/counter/Counter"
|
||||
import "./App.css"
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<Counter />
|
||||
<p>
|
||||
Edit <code>src/App.tsx</code> and save to reload.
|
||||
</p>
|
||||
<span>
|
||||
<span>Learn </span>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://reactjs.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
React
|
||||
</a>
|
||||
<span>, </span>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://redux.js.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Redux
|
||||
</a>
|
||||
<span>, </span>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://redux-toolkit.js.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Redux Toolkit
|
||||
</a>
|
||||
,<span> and </span>
|
||||
<a
|
||||
className="App-link"
|
||||
href="https://react-redux.js.org/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
React Redux
|
||||
</a>
|
||||
</span>
|
||||
</header>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
8
src/app/Router.tsx
Normal file
8
src/app/Router.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useRoutes } from "react-router-dom"
|
||||
import ROUTES from "./routes"
|
||||
|
||||
interface RouterProps {}
|
||||
|
||||
const Router = (props: RouterProps) => useRoutes(ROUTES)
|
||||
|
||||
export default Router
|
||||
0
src/app/config/constants.ts
Normal file
0
src/app/config/constants.ts
Normal file
14
src/app/routes.ts
Normal file
14
src/app/routes.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
const ROUTES = [
|
||||
{
|
||||
path: "/",
|
||||
class: "landing",
|
||||
element: "ComponentsViewer",
|
||||
},
|
||||
{
|
||||
path: "/playground",
|
||||
class: "playground",
|
||||
element: "Playground",
|
||||
},
|
||||
]
|
||||
|
||||
export default ROUTES
|
||||
0
src/app/static/styles/global.scss
Normal file
0
src/app/static/styles/global.scss
Normal file
@@ -1,13 +0,0 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
@@ -1,22 +1,16 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom/client"
|
||||
import { Provider } from "react-redux"
|
||||
import { store } from "./app/store"
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import "./index.css";
|
||||
import Router from "./app/Router"
|
||||
import "./app/static/styles/global.scss"
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement)
|
||||
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
<Router />
|
||||
</Provider>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
import { ReportHandler } from "web-vitals"
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import("web-vitals").then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry)
|
||||
getFID(onPerfEntry)
|
||||
getFCP(onPerfEntry)
|
||||
getLCP(onPerfEntry)
|
||||
getTTFB(onPerfEntry)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default reportWebVitals
|
||||
Reference in New Issue
Block a user