ASP.NET Core 2 Boilerplate with React, Redux and

3r33333. ASP.NET Core 2 Boilerplate with React, Redux and 3r33333.  
Finally, that moment came when I could introduce you to the boiler 3r-38c. React Core Boilerplate
Or, in other words, a ready-made project template on an ASP.NET Core. 3r33333. 3r33333.  
3r33333. Interesting? Welcome under cat. 3r33333. NET Core 2 3r3107. - Actually, the basis.
3r3331. TypeScript 3r3107. - the front end is written on it.
+ Server-side rendering (SSR), then - a library that works both on the client side and on the server using NodeServices.
React Helmet - plugin that allows you to manage the title and meta tags, also works with SSR.
Redux 3r3107. - the application state container.
SASS 3r3107. - CSS styles preprocessor.
Webpack 4 3r3107. - module builder.
3r361. Axios
- provides isomorphic fetch queries.
3r366. ts-nameof
- allows using expressions on TypeScript to get the path to nested objects, ala Html.NameFor in Razor; Works together with the serialization of forms NSerializeJson.
3r33333. Own development written in TypeScript and forks that I fixed:
3r380. domain-wait
- similar to domain-task, but allows using async /await. Designed to wait for server rendering fetch requests.
NVal 3r3107. - forms validator (approximate by API with jquery.validation).
- addition to NVal, allowing using r3r392. js
Make pop-up validation errors in tooltips.
NSerializeJson - forms serializer in JSON with type settings (similar to 3r3999. SerializeJSON
3r3104. bootstrap3-native
- fixed fork native , allowing you to work with elements of bootstrap 3.
3r3113. The purpose of the project 3r3122. 3r33333.  
3r33333. The goal of this project is to support the developers of this stack: to give an opportunity to immediately start developing projects, not bothering with the solution of problems of compatibility of technologies in the stack, their customization. Since the project was created “for people” and contains, in my opinion, an intuitive architecture, it will also be useful for beginners in teaching React, because does not contain problems out of the box for building applications. 3r33333. 3r33333.  
How it all began
3r33333. I am a full-stack developer. Once I liked to write frontend on jQuery - from plugin development to complex sites. However, one day it became clear: the more difficult the project is, the more difficult it is to support sites on this library. Then I decided to study other tools for the development of the frontend. I didn’t like Angular because of my thick abstraction and, having previously studied the advantages and disadvantages of each framework and library, I made a choice in favor of React, which attracted the fact that HTML and TypeScript can be written in one place (.tsx file) without switching between HTML and script files. 3r33333. 3r33333.  
3r33333. Over time, I loved React. But, to be honest, at first I had to use jQuery in React because of the plugins that require it. And then, when I tried to master server rendering due to the well-known problems of SPA and SEO, I learned that jQuery either cannot be friends with it, or it will be a crutch (via jsdom, because a window object is required). I knew that these jQuery plugins would be missed. And since then, I started developing plugins for "Vanilla JS" that are somewhat similar in API to plugins running on jQuery. 3r33333. 3r33333.  
Server rendering
3r33333. A few months ago, Microsoft released an update for Visual Studio 201? which included an ASP.NET Core 2 + TypeScript + React + Redux + Webpack project template with a server prerender using NodeServices. Studying the template, I spent a lot of time to connect SASS via WebPack and update the latter, because studying the documentation, forums and StackOverflow, I did not find the answers I needed to configure this stack, while the documentation was mainly stack with angular. After some time, Microsoft replaced this template with create-react-app without TypeScript and server rendering. Judging by the comments on the Internet, it embarrassed many others, like me. However, I still have that template, and I decided to make my own with blackjack and buns, having dealt with it and solved all the problems at once. 3r33333. 3r33333.  
3r33333. PS: Recently I read that there are so-called opponents of an isomorphic approach to developing applications. What about SEO? Or do you offer to render all paid third-party services? As far as I know, Google can not always index a fat client without a pre-tender. Anyway. 3r33333. 3r33333.  
3r3149. The technical part of the r3r3150. 3r33333.  
React, React Router, Redux
Both libraries have been updated to the latest version, except for react-router-redux, something is wrong with it.
Added examples of their sharing, including the use of Route, along with different Layout (component AppRoute).
3r3168. WebPack and modules
Due to its special structure of WebPack configuration, namely, its separation into server and client parts, it was necessary to use ingenuity to connect the loaders and update WebPack: put a cap for SASS in the WebPack server configuration to collect styles only in the client part (the style-loader requires the presence of the window). And if you use Extract CSS plugin (now MiniCssExtractPlugin for WebPack 4), then, when updating files, the Hot Module Reload (HMR) did not work. Since the original Microsoft templates were configurations for old versions of libraries and the WebPack itself, a lot had to be done.
Aliases for frequently used paths in WebPack and tsconfig.json have been added.
awesome-typescript-loader replaced by babel-loader.
3r3186. NodeServices
3r33333. Documentation on NodeServices was not enough to solve some problems: then the HMR fell off, then something did not work. However, having shown patience, after a month and a half, I finally managed to resolve critical moments: 3r3333366. 3r33333.  
3r33333. ⬝ Instead of the "asp-prerender-module" attribute for the DIV element in View Razor, I had to inject the ISpaPrerender into it:
@inject Microsoft.AspNetCore.SpaServices.Prerendering.ISpaPrerenderer prerenderer 3r33333.  
3r33333. and, manually execute the script: 3r33333.  
    var prerenderResult = await prerenderer.RenderToString (% path to the script load server render%, customDataParameter: data);    
3r33333. Then, from the prerenderResult object, you can drag the rendered HTML React and React Helmet into the BODY /DIV and HEAD blocks, respectively. 3r33333. 3r33333.  
3r33333. ⬝ The domain-task NPM package did not allow using async /await and tools for fetch requests except isomorfic-fetch and fetch from the same npm package. This is fixed by me in the domain-wait package. Now fetch requests are more pleasant to write, especially using axios. 3r33333. 3r33333.  

Application architecture 3r33232. 3r33333.  
3r33333. From personal experience I made some work, for example, in all methods of services (except for authorization), to accept ServiceUser and return a Result object with result or errors. Both such objects + an imitation of the authorization service are already incorporated in the boilerplate. I am an opponent of Identity, and authorization is not suitable for everyone. So, nothing superfluous, and the imitation of authorization is easy to cut out (AccountService, Middleware, ControllerBase). 3r33333. 3r33333.  

  • Two React's Layout - guest and for authorized users.  
  • The plug-ins written by me are also connected, which are available in NPM and are actively used. Now it is easy to integrate forms with validation, and pull out JSON data from them. All this is demonstrated in the example in the template.  
  • On the frontend side, all fetch requests are encapsulated into services that are also isomorphic, i.e. can work on the server side.  
  • The project provides an example of how, in my opinion, the application should look like: an easily readable and intuitive application structure and code.  
File structure [/b]
    | .gitignore
| AppSettings.cs
| appsettings.Development.json
| appsettings.json
| Constants.cs # Constants, contain keys to fake authorization cookies.
| package.json # NPM file.
| Program.cs # Application entry point.
| ReactSSR.WebApp.csproj # Visual Studio 2017 project file.
| Startup.cs # Contains application settings and middleware fake authorization.
| tsconfig.json # TypeScript configuration file.
| webpack.config.js # Contains WebPack configurations for building server and client bundles.
| webpack.config.vendor.js # Contains WebPack configurations for the server and client Vendor bundles.
+ --- ClientApp
| | boot-client.tsx # Input point for rendering frontend in the browser.
| | boot-server.tsx # Input point for rendering frontend on the server side.
| | configureStore.ts # Redux repository configuration.
| | global.d.ts # Global definitions of modules and TypeScript types for the frontend (for example, ts-nameof, * .png, etc.) 3r3727. | | Globals.ts # Encapsulates the isomorphic state of the application (for example, authorization data).
| | routes.tsx # Routing settings for frontend.
| | Ui.ts # Enables helpers for the UI (for example, tooltips).
| | utils.ts # Contains useful methods.
| |
| + --- components # Components (not pages).
| | + --- person
| | | PersonEditor.tsx # Component included in the sample.
| | |
| | --- shared # Common components.
| | AppRoute.tsx # Component for building routes with more than one layout.
| | ErrorBoundary.tsx # Component based on the "error boundary" pattern. When wrapped in it, it helps to catch errors in other components.
| | Footer.tsx # Footer for the authorized zone.
| | Loader.tsx # Component containing the download indicator.
| | PagingBar.tsx # Page Switch.
| | TopMenu.tsx # Top menu for authorized zone.
| |
| + --- images
| | logo.png # Boilerplate logo.
| |
| + --- layouts # Layers (zones).
| | AuthorizedLayout.tsx
| | GuestLayout.tsx
| |
| + --- models # TypeScript models used in the application.
| | ILoginModel.ts
| | IPersonModel.ts
| | IServiceUser.ts
| | ISessionData.ts
| | Result.ts # Implementing the "Result" pattern.
| |
| + --- pages # Pages of the application.
| | ExamplePage.tsx
| | HomePage.tsx
| | LoginPage.tsx
| |
| + --- services # Isomorphic JS services that encapsulate logic for working with queries.
| | AccountService.ts # JS-service fake authorization.
| | PersonService.ts # JS service is an example.
| | ServiceBase.ts # Basic abstract TS-class for constructing isomorphic JS-services.
| |
| + --- store # Redux storage.
| | index.ts # Definitions for Redux repositories.
| | LoginStore.ts
| | PersonStore.ts # Storage for an example.
| |
| --- styles
| authorizedLayout.scss # Styles for the authorized zone.
| guestLayout.scss # Styles for the guest zone.
| loader.scss # Styles for the download indicator.
| main.scss # Common styles.
| preloader.css # Styles for the initial loading indicator.
+ --- Controllers
| AccountController.cs # Controller fake authorization.
| ControllerBase.cs # Encapsulates properties and settings for fake authorization.
| MainController.cs # Input point controller.
| PersonController.cs # Sample controller
+ --- Extensions
| ServiceCollectionExtensions.cs # Encapsulates methods that allow Lazy DI containers to be determined.
+ --- Infrastructure # Folder containing basic infrastructure modelsUktura application.
| Result.cs # Implementing the "Result" pattern on the server side.
| ServiceBase.cs # The base class for all services that implement the Facade /Facade pattern.
+ --- Models
| LoginModel.cs # Model for fake authorization.
| PersonModel.cs # Model for example.
| ServiceUser.cs
| SessionData.cs # Data model of an isomorphic session.
+ --- Services # Contains services implementing the "Facade" pattern.
| AccountService.cs # Service fake accounts.
| PersonService.cs # Service example.
+ --- Views
| | _ViewImports.cshtml
| | _ViewStart.cshtml
| |
| + --- Main
| | Index.cshtml # An application entry point containing the root container in which the frontend is rendered.
| |
| --- Shared
| Error.cshtml
--- wwwroot # Root folder where bundles will be collected.

3r33333. 3r33333. 3r33333.  
3r33333. That's all. Thank you all for your attention and, of course, Happy Coding! 3r33333. 3r33333.
! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//"""_mediator") () (); 3r33333.
+ 0 -

Add comment