From feeaa1ba25cce093169bd135c18a2e764ac1c3b5 Mon Sep 17 00:00:00 2001 From: Marko Stijak Date: Wed, 16 Jun 2021 10:34:38 +0200 Subject: [PATCH] Adding app content --- .editorconfig | 17 ++++ .gitignore | 2 + LICENSE => LICENSE.md | 2 +- README.md | 19 ++++- app/components/Hamburger.scss | 41 +++++++++ app/components/index.scss | 1 + app/index.html | 15 ++++ app/index.js | 23 +++++ app/index.scss | 8 ++ app/layout/Controller.js | 16 ++++ app/layout/index.js | 60 +++++++++++++ app/layout/index.scss | 112 ++++++++++++++++++++++++ app/polyfill.js | 3 + app/routes/_template/Controller.js | 5 ++ app/routes/_template/index.js | 9 ++ app/routes/_template/index.scss | 1 + app/routes/about/index.js | 34 ++++++++ app/routes/about/index.scss | 1 + app/routes/dashboard/Controller.js | 33 +++++++ app/routes/dashboard/index.js | 123 +++++++++++++++++++++++++++ app/routes/dashboard/index.scss | 52 +++++++++++ app/routes/default/index.js | 78 +++++++++++++++++ app/routes/default/index.scss | 1 + app/routes/index.js | 32 +++++++ app/routes/index.scss | 4 + app/routes/users/Editor.js | 76 +++++++++++++++++ app/routes/users/EditorController.js | 39 +++++++++ app/routes/users/List.js | 50 +++++++++++ app/routes/users/ListController.js | 31 +++++++ app/routes/users/api.js | 55 ++++++++++++ app/routes/users/index.js | 15 ++++ app/routes/users/index.scss | 28 ++++++ assets/img/welcome.png | Bin 0 -> 43805 bytes config/babel.config.js | 28 ++++++ config/webpack.config.js | 57 +++++++++++++ config/webpack.dev.js | 37 ++++++++ config/webpack.prod.js | 51 +++++++++++ package.json | 39 +++++++++ 38 files changed, 1195 insertions(+), 3 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitignore rename LICENSE => LICENSE.md (96%) create mode 100644 app/components/Hamburger.scss create mode 100644 app/components/index.scss create mode 100644 app/index.html create mode 100644 app/index.js create mode 100644 app/index.scss create mode 100644 app/layout/Controller.js create mode 100644 app/layout/index.js create mode 100644 app/layout/index.scss create mode 100644 app/polyfill.js create mode 100644 app/routes/_template/Controller.js create mode 100644 app/routes/_template/index.js create mode 100644 app/routes/_template/index.scss create mode 100644 app/routes/about/index.js create mode 100644 app/routes/about/index.scss create mode 100644 app/routes/dashboard/Controller.js create mode 100644 app/routes/dashboard/index.js create mode 100644 app/routes/dashboard/index.scss create mode 100644 app/routes/default/index.js create mode 100644 app/routes/default/index.scss create mode 100644 app/routes/index.js create mode 100644 app/routes/index.scss create mode 100644 app/routes/users/Editor.js create mode 100644 app/routes/users/EditorController.js create mode 100644 app/routes/users/List.js create mode 100644 app/routes/users/ListController.js create mode 100644 app/routes/users/api.js create mode 100644 app/routes/users/index.js create mode 100644 app/routes/users/index.scss create mode 100644 assets/img/welcome.png create mode 100644 config/babel.config.js create mode 100644 config/webpack.config.js create mode 100644 config/webpack.dev.js create mode 100644 config/webpack.prod.js create mode 100644 package.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..abe470b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*.js] +indent_style = space +indent_size = 4 +end_of_line = lf + +[*.ts] +indent_style = space +indent_size = 4 +end_of_line = lf + +[*.scss] +indent_style = space +indent_size = 4 +end_of_line = lf + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b0a5c34 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/node_modules/ +/dist/ diff --git a/LICENSE b/LICENSE.md similarity index 96% rename from LICENSE rename to LICENSE.md index 4b7869d..64b8322 100644 --- a/LICENSE +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Codaxy +Copyright (c) 2021 Codaxy d.o.o. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 0125dab..99b5a3c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,17 @@ -# cxjs-app-template-basic -Basic CxJS application template +# Basic application template for CxJS + +To start the application, run: + +```bash +npm start +``` + +To build the application, run: + +```bash +npm run build +``` + +### License + +[MIT](./License.md) diff --git a/app/components/Hamburger.scss b/app/components/Hamburger.scss new file mode 100644 index 0000000..4c0ce9e --- /dev/null +++ b/app/components/Hamburger.scss @@ -0,0 +1,41 @@ +.hamburger { + $size: 20px; + $icon-size: 16px; + $thickness: 2px; + $color: rgba(255, 255, 255, 0.8); + + display: block; + position: relative; + width: $size; + height: $size; + margin-right: 1rem; + flex-shrink: 0; + + &:after, + &:before { + background-color: $color; + transition: all 0.2s linear; + content: " "; + display: block; + position: absolute; + height: $thickness; + left: ($size - $icon-size) / 2; + right: ($size - $icon-size) / 2; + top: ($size/2) - ceil($thickness/2); + } + &:before { + box-shadow: $color 0 (-$icon-size/2 + $thickness); + } + &:after { + box-shadow: $color 0 ($icon-size/2) - $thickness; + } + + &.open { + &:before { + box-shadow: $color 0 (-$icon-size/2 + $thickness + 3px); + } + &:after { + box-shadow: $color 0 ($icon-size/2 - $thickness - 3px); + } + } +} diff --git a/app/components/index.scss b/app/components/index.scss new file mode 100644 index 0000000..0526c9c --- /dev/null +++ b/app/components/index.scss @@ -0,0 +1 @@ +@import "Hamburger"; diff --git a/app/index.html b/app/index.html new file mode 100644 index 0000000..b172272 --- /dev/null +++ b/app/index.html @@ -0,0 +1,15 @@ + + + + + + + Cx App + + + +
+
+ + + \ No newline at end of file diff --git a/app/index.js b/app/index.js new file mode 100644 index 0000000..bf2db9b --- /dev/null +++ b/app/index.js @@ -0,0 +1,23 @@ +import {Store} from "cx/data"; +import {Url, History, Widget, startHotAppLoop} from "cx/ui"; +import {Timing, Debug} from "cx/util"; + +//css +import "./index.scss"; + +//store +const store = new Store(); + +//routing +Url.setBaseFromScript("app*.js"); +History.connect(store, "url"); + +//debug +Widget.resetCounter(); +Timing.enable("app-loop"); +Debug.enable("app-data"); + +//app loop +import Routes from "./routes"; + +startHotAppLoop(module, document.getElementById("app"), store, Routes); diff --git a/app/index.scss b/app/index.scss new file mode 100644 index 0000000..fe2170f --- /dev/null +++ b/app/index.scss @@ -0,0 +1,8 @@ +$cx-include-global-rules: true; + +@import "~cx/src/variables"; +@import "~cx/src/index"; + +@import "components/index"; +@import "layout/index"; +@import "routes/index"; diff --git a/app/layout/Controller.js b/app/layout/Controller.js new file mode 100644 index 0000000..4e2e3da --- /dev/null +++ b/app/layout/Controller.js @@ -0,0 +1,16 @@ +import { Controller } from "cx/ui"; + +export default class extends Controller { + onInit() { + this.store.init("layout.aside.open", window.innerWidth >= 800); + + this.addTrigger("navigation", ["url"], () => { + if (window.innerWidth < 800) + this.store.set("layout.aside.open", false); + }); + } + + onMainClick(e, { store }) { + if (window.innerWidth < 800) store.set("layout.aside.open", false); + } +} diff --git a/app/layout/index.js b/app/layout/index.js new file mode 100644 index 0000000..1125751 --- /dev/null +++ b/app/layout/index.js @@ -0,0 +1,60 @@ +import { Link } from "cx/widgets"; +import { ContentPlaceholder } from "cx/ui"; +import Controller from "./Controller"; + +export default ( + +
+
+ +
+
+ { + store.toggle("layout.aside.open"); + }} + /> + +
+ +
+
+); diff --git a/app/layout/index.scss b/app/layout/index.scss new file mode 100644 index 0000000..792a438 --- /dev/null +++ b/app/layout/index.scss @@ -0,0 +1,112 @@ +$header-color: #a73232; +$aside-width: 260px; +$small-device-width: 800px; + +#app, +.layout { + height: 100%; +} + +.header { + padding: 1.5em; + background: $header-color; + position: fixed; + transition: all 0.2s linear; + left: 0; + top: 0; + right: 0; + box-shadow: 3px 2px 5px rgba(0, 0, 0, 0.26); + display: flex; + align-items: center; + + h2 { + line-height: 1; + font-size: 1.5rem; + margin: 0; + color: white; + } + + .layout.nav & { + transform: translateX($aside-width); + @media screen and (min-width: $small-device-width) { + left: $aside-width; + transform: none; + } + } +} + +.aside { + position: fixed; + left: 0; + top: 0; + bottom: 0; + width: $aside-width; + background: white; + box-shadow: 0 0 1px rgba(0, 0, 0, 0.26); + font-size: 13px; + + transform: translateX(-300px); + transition: transform 0.2s linear; + + .layout.nav & { + transform: none; + } + + h1 { + line-height: 3rem; + margin: 0; + padding: 0.5em; + text-align: center; + box-shadow: 0 0 1px rgba(0, 0, 0, 0.26); + text-transform: uppercase; + font-size: 1.5rem; + } + + dt { + padding: 0.5rem 0.5rem 0.5rem 2rem; + font-weight: bold; + } + + dl .cxb-link { + padding: 0.5rem; + display: block; + color: inherit; + + &.cxs-active { + color: $header-color; + } + } +} + +.main { + padding: 5.5rem 1rem 1rem; + transition: all 0.2s linear; + height: 100%; + box-sizing: border-box; + display: block; + + .layout.nav & { + transform: translateX($aside-width); + @media screen and (min-width: $small-device-width) { + margin-left: $aside-width; + transform: none; + } + } +} + +h3 { + color: $header-color; +} + +p { + max-width: 40em; +} + +.cxb-section.cxm-card { + background: white; + box-shadow: 0 0 5px rgba(0, 0, 0, 0.26); + border-radius: 1px; +} + +.layout.nav { +} diff --git a/app/polyfill.js b/app/polyfill.js new file mode 100644 index 0000000..156080b --- /dev/null +++ b/app/polyfill.js @@ -0,0 +1,3 @@ +import "core-js/stable"; +import "regenerator-runtime/runtime"; +import 'whatwg-fetch'; diff --git a/app/routes/_template/Controller.js b/app/routes/_template/Controller.js new file mode 100644 index 0000000..16e2117 --- /dev/null +++ b/app/routes/_template/Controller.js @@ -0,0 +1,5 @@ +export default { + onInit() { + + } +} diff --git a/app/routes/_template/index.js b/app/routes/_template/index.js new file mode 100644 index 0000000..594c2b0 --- /dev/null +++ b/app/routes/_template/index.js @@ -0,0 +1,9 @@ +//import { HtmlElement } from "cx/widgets"; + +import Controller from "./Controller"; + +export default ( + +
+ +); diff --git a/app/routes/_template/index.scss b/app/routes/_template/index.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/routes/_template/index.scss @@ -0,0 +1 @@ + diff --git a/app/routes/about/index.js b/app/routes/about/index.js new file mode 100644 index 0000000..3e7ab0c --- /dev/null +++ b/app/routes/about/index.js @@ -0,0 +1,34 @@ +import { Link, Section } from "cx/widgets"; + +export default ( + +

About

+
+

+ This is an application generated using Cx CLI. It's just a + skeleton that provides a basic layout and a couple of demo + pages. +

+ +
Layout
+

+ This is a simple responsive layout with a side navigation that + is initially closed on screens less than a 1000px wide. +

+ +
Dashboard Page
+

+ A really simple dashboard with hardcoded data. It's there just + to remind you that CxJS offers a nice charting package that can + be used to build dashboards. +

+ +
Users Page
+

+ A sample admin page demonstrating CRUD operations and search + functionality. +

+ Back +
+
+); diff --git a/app/routes/about/index.scss b/app/routes/about/index.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/routes/about/index.scss @@ -0,0 +1 @@ + diff --git a/app/routes/dashboard/Controller.js b/app/routes/dashboard/Controller.js new file mode 100644 index 0000000..fc28999 --- /dev/null +++ b/app/routes/dashboard/Controller.js @@ -0,0 +1,33 @@ +import { Controller } from "cx/ui"; + +export default class extends Controller { + onInit() { + this.store.init("bars", [ + { + day: "Mo", + value: 500, + colorIndex: 12 + }, + { + day: "Tu", + value: 900, + colorIndex: 9 + }, + { + day: "We", + value: 850, + colorIndex: 10 + }, + { + day: "Th", + value: 950, + colorIndex: 9 + }, + { + day: "Fr", + value: 1000, + colorIndex: 8 + } + ]); + } +} diff --git a/app/routes/dashboard/index.js b/app/routes/dashboard/index.js new file mode 100644 index 0000000..20fcf86 --- /dev/null +++ b/app/routes/dashboard/index.js @@ -0,0 +1,123 @@ +import { Section, FlexRow, Repeater, Rescope } from "cx/widgets"; +import { + CategoryAxis, + Chart, + Column, + Gridlines, + LineGraph, + Marker, + NumericAxis, + PieChart, + PieSlice +} from "cx/charts"; +import { Svg, Text } from "cx/svg"; + +import Controller from "./Controller"; + +export default ( + +

Dashboard

+ + +
+
Counter
+
+
5,253
+
Users
+
+ +
+ +
+
Bars
+
+ + + + + + + + +
+ +
+ +
+
Line
+
+ + + + + + + + + +
+ +
+
+
Donut
+
+ + + + + + + 80.1% + + +
+ +
+
+
+
+); diff --git a/app/routes/dashboard/index.scss b/app/routes/dashboard/index.scss new file mode 100644 index 0000000..218f0c5 --- /dev/null +++ b/app/routes/dashboard/index.scss @@ -0,0 +1,52 @@ +.kpi-header { + margin: 0 0 10px 0; + text-align: center; + text-transform: uppercase; +} + +.kpi-footer { + margin-top: 10px; + text-align: center; + text-transform: uppercase; + color: gray; +} + +.kpi-main { + height: 115px; +} + +.kpi-value { + font-size: 50px; + text-align: right; + padding-top: 20px; +} + +.kpi-value-text { + font-size: 15px; + text-align: right; + text-transform: uppercase; + font-weight: bold; + margin-top: -10px; +} + +.donut-text { + font-size: 20px; +} + +.line-marker circle { + stroke: white; + stroke-width: 4px; + transition: stroke 0.3s ease-in-out; +} + +.line-marker circle:hover { + stroke: #99e4ee; +} + +.cxe-numericaxis-label { + font-size: 10px; +} + +.cxe-categoryaxis-label { + font-size: 10px; +} diff --git a/app/routes/default/index.js b/app/routes/default/index.js new file mode 100644 index 0000000..559d89b --- /dev/null +++ b/app/routes/default/index.js @@ -0,0 +1,78 @@ +import { Section } from "cx/widgets"; + +export default ( + +

Home

+ +
+ +

Your app is now running. Let's get started.

+
1. Routing
+

+ Navigate through the pages to see if all pages load correctly. + Bear in mind that routing is done completely client-side. No + server calls are made to load pages. This is ok for smaller + apps. If your app gets big and slow, you should consider{" "} + + Code Splitting + . +

+ +
2. Hot Module Replacement (HMR)
+

+ This app is using webpack development server which offers hot + module replacement. After you can change the source code the + browser will automatically update the page on each save without + refreshing. There is an error on this page, let's fix it. Next + section should be called SCSS instead of CSS. Open{" "} + app/routes/default/index.js + and change the text. +

+ +
3. CSS
+

+ CSS for this application is generated using Sass(SCSS) + configured as a webpack plugin. Sass provides variables, mixins + and other helpful features for authoring CSS. Let's try it. Go + to app/layout/index.scss and change the{" "} + $header-color. + #3b4888 looks nice. You should also consider using + one of + + available CxJS themes + . +

+ +
Next Steps
+

+ If you haven't done so already, you should now star CxJS on + + GitHub + . While there, you can glance at the source code of CxJS and + our demo applications. There are plenty of{" "} + + examples on our website + + and you should definitely get familiar{" "} + + CxJS documentation + . If you have any problems you may{" "} + contact us for support, ask a + question on{" "} + + StackOverflow + + or report{" "} + + a bug at GitHub + . +

+
+
+); diff --git a/app/routes/default/index.scss b/app/routes/default/index.scss new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/routes/default/index.scss @@ -0,0 +1 @@ + diff --git a/app/routes/index.js b/app/routes/index.js new file mode 100644 index 0000000..b349b0f --- /dev/null +++ b/app/routes/index.js @@ -0,0 +1,32 @@ +import {Route, Section, Sandbox} from "cx/widgets"; +import {FirstVisibleChildLayout} from "cx/ui"; + +import AppLayout from "../layout"; + +import Default from "./default"; +import About from "./about"; +import Dashboard from "./dashboard"; +import UserRoutes from "./users"; + +export default () => + + + + + + + + + + + +
+ This page doesn't exists. Please check your URL. +
+
+
; diff --git a/app/routes/index.scss b/app/routes/index.scss new file mode 100644 index 0000000..3a90770 --- /dev/null +++ b/app/routes/index.scss @@ -0,0 +1,4 @@ +@import 'about/index'; +@import 'default/index'; +@import 'dashboard/index'; +@import 'users/index'; diff --git a/app/routes/users/Editor.js b/app/routes/users/Editor.js new file mode 100644 index 0000000..ded2171 --- /dev/null +++ b/app/routes/users/Editor.js @@ -0,0 +1,76 @@ +import { + Section, + Button, + FlexRow, + LinkButton, + TextField, + Checkbox, + Rescope, + ValidationGroup +} from "cx/widgets"; +import { LabelsTopLayout } from "cx/ui"; + +import Controller from "./EditorController"; +import "cx/widgets/icons"; + +export default ( + + +

Edit User

+
+ + + + + Enabled +
+ + + + Cancel + + + +
+
+
+
+); diff --git a/app/routes/users/EditorController.js b/app/routes/users/EditorController.js new file mode 100644 index 0000000..0fab343 --- /dev/null +++ b/app/routes/users/EditorController.js @@ -0,0 +1,39 @@ +import { Controller, History } from "cx/ui"; +import { getUser, postUser, deleteUser, putUser } from "./api"; + +export default class extends Controller { + onInit() { + //As Rescope is used $route params are available under $root.$route + let userId = this.store.get("$root.$route.userId"); + + if (userId == "new") { + this.store.set("user", { + display: "New User" + }); + } else { + getUser(userId).then(data => { + this.store.set("user", data); + }); + } + } + + onSave() { + let { invalid, user } = this.store.getData(); + + let userId = this.store.get("$root.$route.userId"); + + let promise = userId == "new" ? postUser(user) : putUser(userId, user); + + promise.then(() => { + History.pushState({}, null, "~/users"); + }); + } + + onDelete() { + let userId = this.store.get("$root.$route.userId"); + + deleteUser(userId).then(() => { + History.pushState({}, null, "~/users"); + }); + } +} diff --git a/app/routes/users/List.js b/app/routes/users/List.js new file mode 100644 index 0000000..429e1c0 --- /dev/null +++ b/app/routes/users/List.js @@ -0,0 +1,50 @@ +import { + Section, + FlexRow, + TextField, + Link, + LinkButton, + Repeater, + Rescope +} from "cx/widgets"; + +import Controller from "./ListController"; +import "cx/widgets/icons"; + +export default ( + +

Users

+ +
+ + + + Add User + + +
+ + + +
+ +
+ @ +
+ +
+
+
+
+); diff --git a/app/routes/users/ListController.js b/app/routes/users/ListController.js new file mode 100644 index 0000000..b0d02d7 --- /dev/null +++ b/app/routes/users/ListController.js @@ -0,0 +1,31 @@ +import { Controller } from "cx/ui"; +import { debounce } from "cx/util"; +import { queryUsers } from "./api"; + +let lastQueryId = 0; + +export default class extends Controller { + onInit() { + this.addTrigger("search", ["search"], debounce(::this.load, 200)); + this.load(); + } + + load() { + let q = this.store.get("search"); + this.store.set("status", "loading"); + let queryId = ++lastQueryId; + queryUsers(q) + .then(data => { + //only the last query matters + if (queryId === lastQueryId) { + this.store.set("results", data); + this.store.set("status", "ok"); + } + }) + .catch(() => { + if (queryId === lastQueryId) { + this.store.set("status", "error"); + } + }); + } +} diff --git a/app/routes/users/api.js b/app/routes/users/api.js new file mode 100644 index 0000000..26cc912 --- /dev/null +++ b/app/routes/users/api.js @@ -0,0 +1,55 @@ +//Fake RESTful API + +let data = Array.from({ length: 30 }, (_, i) => ({ + id: i + 1, + username: `user${i + 1}`, + display: `User ${i + 1}`, + enabled: true +})); + +export function queryUsers(q) { + return new Promise(resolve => { + let result = data.filter(user => !q || user.username.indexOf(q) !== -1); + //simulate server response delay + setTimeout(() => resolve(result), 100); + }); +} + +export function getUser(id) { + return new Promise(resolve => { + let index = data.findIndex(u => u.id == id); + resolve(data[index]); + }); +} + +export function putUser(id, user) { + return new Promise(resolve => { + let index = data.findIndex(u => u.id == id); + if (index === -1) throw new Error("User not found!"); + let result = (data[index] = { + ...data[index], + ...user, + id: id + }); + resolve(result); + }); +} + +export function postUser(user) { + return new Promise(resolve => { + let id = data.length + 1; + let result = { + ...user, + id: id + }; + data.push(result); + resolve(result); + }); +} + +export function deleteUser(id) { + return new Promise(resolve => { + data = data.filter(u => u.id != id); + resolve(); + }); +} diff --git a/app/routes/users/index.js b/app/routes/users/index.js new file mode 100644 index 0000000..e4fa8ea --- /dev/null +++ b/app/routes/users/index.js @@ -0,0 +1,15 @@ +import { Route } from "cx/widgets"; + +import List from "./List"; +import Editor from "./Editor"; + +export default ( + + + + + + + + +); diff --git a/app/routes/users/index.scss b/app/routes/users/index.scss new file mode 100644 index 0000000..9c766b4 --- /dev/null +++ b/app/routes/users/index.scss @@ -0,0 +1,28 @@ +.user-card { + color: inherit; + width: 250px; + + &:hover { + text-decoration: none; + border-color: $header-color; + } +} + +.user-card-body { + box-sizing: border-box; + //border: 1px solid lightgray; + padding-left: 60px; + position: relative; + height: 70px; + + img { + position: absolute; + top: 10px; + left: 10px; + } + + &:hover { + border: 1px solid $header-color; + margin: -1px; + } +} diff --git a/assets/img/welcome.png b/assets/img/welcome.png new file mode 100644 index 0000000000000000000000000000000000000000..19baf6ac570256fa0a597b3adf3c1b74971756b7 GIT binary patch literal 43805 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 path.join(__dirname, "../", p || ""); + +module.exports = { + resolve: { + alias: { + app: p("app") + //uncomment the line below to alias cx-react to cx-preact or some other React replacement library + //'cx-react': 'cx-preact', + } + }, + + module: { + rules: [ + { + test: /\.js$/, + //add here any ES6 based library + include: /[\\\/](app|cx|cx-react|cx-theme-\w*)[\\\/]/, + use: { + loader: "babel-loader", + options: babelCfg + } + }, + { + test: /\.(png|jpg)/, + use: "file-loader" + } + ] + }, + entry: { + vendor: ["cx-react", p("app/polyfill.js")], + app: [p("app/index.js")] + }, + plugins: [ + new HtmlWebpackPlugin({ + template: p("app/index.html") + }), + ], + optimization: { + runtimeChunk: 'single' + }, + cache: { + type: 'filesystem', + + buildDependencies: { + config: [ + __filename, + p('config/webpack.dev.js'), + p('config/webpack.prod.js'), + p('config/babel.config.js') + ] + } + } +}; diff --git a/config/webpack.dev.js b/config/webpack.dev.js new file mode 100644 index 0000000..eaada40 --- /dev/null +++ b/config/webpack.dev.js @@ -0,0 +1,37 @@ +const + webpack = require("webpack"), + { merge } = require("webpack-merge"), + common = require("./webpack.config"); + +module.exports = merge(common, { + mode: 'development', + + module: { + rules: [ + { + test: /\.scss$/, + use: ["style-loader", "css-loader", "sass-loader"] + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"] + } + ] + }, + + plugins: [new webpack.HotModuleReplacementPlugin()], + + output: { + publicPath: "/" + }, + + devtool: "eval", + + devServer: { + hot: true, + port: 8765, + noInfo: false, + inline: true, + historyApiFallback: true + } +}); diff --git a/config/webpack.prod.js b/config/webpack.prod.js new file mode 100644 index 0000000..85c9fe4 --- /dev/null +++ b/config/webpack.prod.js @@ -0,0 +1,51 @@ +const + webpack = require('webpack'), + MiniCssExtractPlugin = require("mini-css-extract-plugin"), + CopyWebpackPlugin = require("copy-webpack-plugin"), + { merge } = require("webpack-merge"), + common = require("./webpack.config"), + path = require("path"), + p = p => path.join(__dirname, "../", p || ""); + +module.exports = merge(common, { + mode: 'production', + + output: { + path: p("dist"), + publicPath: "/", + filename: "[name].[chunkhash].js", + chunkFilename: "[name].[chunkhash].js", + hashDigestLength: 6 + }, + + module: { + rules: [ + { + test: /\.scss$/, + use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"] + }, + { + test: /\.css$/, + use: [MiniCssExtractPlugin.loader, "css-loader"] + } + ] + }, + + plugins: [ + new webpack.DefinePlugin({ + "process.env.NODE_ENV": JSON.stringify("production") + }), + new MiniCssExtractPlugin({ + filename: "[name].[hash].css", + chunkFilename: "[name].[hash].css" + }), + new CopyWebpackPlugin({ + patterns: [ + { + from: p("./assets"), + to: p("./dist/assets") + } + ] + }) + ] +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..933d6a5 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "cx-app-tpl", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "start": "webpack-dev-server --config config/webpack.dev.js --open", + "build": "webpack --config config/webpack.prod.js" + }, + "private": true, + "dependencies": { + "core-js": "^3.9.1", + "cx": "^21.1.7", + "cx-react": "^17.10.0", + "react": "^17.0.1", + "react-dom": "^17.0.1", + "regenerator-runtime": "^0.13.7", + "whatwg-fetch": "^3.6.1" + }, + "devDependencies": { + "@babel/core": "^7.13.8", + "@babel/preset-env": "^7.13.9", + "babel-loader": "^8.2.2", + "babel-preset-cx-env": "^21.1.1", + "copy-webpack-plugin": "^6.3.1", + "css-loader": "^5.0.2", + "file-loader": "^6.2.0", + "html-webpack-plugin": "^5.2.0", + "inline-manifest-webpack-plugin": "^4.0.0", + "json-loader": "^0.5.4", + "mini-css-extract-plugin": "^1.3.8", + "node-sass": "^5.0.0", + "sass-loader": "^11.0.1", + "style-loader": "^2.0.0", + "webpack": "^5.24.1", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^3.11.2", + "webpack-merge": "^5.4.0" + } +}