Saturday, 17 June 2023

Learning CakePhp3

013: add using job

012: add using email

011: add using HelloShell 

010: add using relation, baseService

009: add check auth in view 

007: add using element in view

006: add using beforeRender 

005: add DemoMiddleware

004: add register, login, logout for user 

003: add CRUD for users

002: add CRUD for products 

001: add migrate products

first commit 

Adonis web using Inertia

- Install Adonisjs Web

yarn create adonis-ts-app hello-world
 
❯ Select the project structure · web
❯ Enter the project name · hello-world
❯ Setup eslint? (y/N) · false
❯ Configure webpack encore for compiling frontend assets? (y/N) · true

- Install inertia 

yarn add  @eidellev/inertia-adonisjs
node ace configure @eidellev/inertia-adonisjs
❯ Enter the `.edge` view file you would like to use as your root template · app
❯ Would you like to use SSR? (y/N) · false
❯ Which client-side adapter would you like to set up? · @inertiajs/react
[ wait ]  Installing dependencies: @inertiajs/react, react, react-dom, @types/react, @types/react-dom ..

-  Register Inertia middleware

// start/kernel.ts
Server.middleware.register([
() => import('@ioc:Adonis/Core/BodyParser'),
() => import('@ioc:EidelLev/Inertia/Middleware'),
]); 

- Configure Webpack-Encore for React in Typescript: By default Webpack Encore (AdonisJS asset bundler) is configured for JS, we want to use TS in our app, let's configure support for TS.

yarn add ts-loader @babel/preset-react --save-dev 
=> have file  resources\views\app.edge.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/png" href="/favicon.ico">
@entryPointStyles('app')
@entryPointScripts('app')
<title>csr-adonis-inertia-react</title>
</head>
<body>
@inertia
</body>
</html>

- Modify the entrypoint, edit webpack.config.js changing the following:

// webpack.config.js
Encore.addEntry('app', './resources/js/app.js')
into:
Encore.addEntry('app', './resources/js/app.tsx')
Encore.enableTypeScriptLoader()
Encore.enableReactPreset()

// Rename ./resources/js/app.js to ./resources/js/app.tsx.
resources/js/app.tsx.

// Create a file ./resources/js/tsconfig.json, with contents:
{
"include": ["**/*"],
"compilerOptions": {
"lib": ["DOM"],
"jsx": "react",
"esModuleInterop": true
}
}

// tsconfig.json at the root of your project add the following to the "compilerOptions" section
"lib": ["DOM"],
"jsx": "react",

- Configure the app entrypoint file resources/js/app.tsx to contain

import { InertiaApp } from '@inertiajs/inertia-react'
import React from 'react'
import ReactDOM from 'react-dom'
import '../css/app.css'

// initial page object with props from server
const root = document.getElementById('app')
const page = JSON.parse(root?.dataset.page as string)

// dynamically load specified page component from "resources/js/Pages/." dir
async function resolver(pageName) {
const module = await import(`./Pages/${pageName}`)
return module.default
}

function App() {
return <InertiaApp initialPage={page} resolveComponent={resolver} initialComponent={''} />
}

ReactDOM.render(<App />, root)

- Create a test component

import React from 'react'

const Test = ({exampleProp}) => <div>Hello world, from {exampleProp}!)</div>

export default Test

- Create a test route

// start/routes.ts
import Route from '@ioc:Adonis/Core/Route'

Route.get('/test', async ({ inertia }) => {
return inertia.render('Test', { exampleProp: 'inertia' })
})

* show result

node ace serve --watch

* Errors

- TS2688: Cannot find type definition file for 'pino-std-serializers'.

yarn add @types/pino-std-serializers

- TS2307: Cannot find module '@inertiajs/inertia-react'

yarn add @inertiajs/inertia-react

-  Error: Can't resolve '@inertiajs/inertia'

yarn add @inertiajs/inertia

- Warning: React-dom.development.js:86: ReactDOM.render is no longer supported in React 18. Use createRoot instead. Until you switch to the new API, your app will behave as if it's running React 17

// update resources/js/app.tsx
import { InertiaApp } from '@inertiajs/inertia-react';
import React from 'react';
import { createRoot } from 'react-dom/client';
import '../css/app.css';

// initial page object with props from server
const root = document.getElementById('app');
const page = JSON.parse(root?.dataset.page as string);

// dynamically load specified page component from "resources/js/Pages/." dir
async function resolver(pageName) {
const module = await import(`./Pages/${pageName}`);
return module.default;
}

function App() {
return <InertiaApp initialPage={page} resolveComponent={resolver} initialComponent={''} />;
}

createRoot(root).render(<App />);

Source git: https://github.com/phong2018/learning-adonisjs-web-inertia

Reference: guide

Thank you.  

Monday, 5 June 2023

Adonis using Reactjs for Frontend

- configure compile React assets

yarn add adonis-mix-asset && yarn add -D laravel-mix laravel-mix-tailwind;

- setup provider, commands, webpack.mix.js for adonis

node ace invoke adonis-mix-asset;

- install package for hot loading, 

yarn add -D @babel/preset-react babel-loader @pmmmwh/react-refresh-webpack-plugin react-refresh;

- config webpack.mix.js

const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin')
const webpack = require('webpack')
const mix = require('laravel-mix')
require('laravel-mix-tailwind')
const isDevelopment = process.env.NODE_ENV !== 'production'
mix
.setPublicPath('public')
.js('resources/client/index.js', 'public/js/')
.react()
.sass('resources/assets/scss/index.scss', 'public/css/')
.tailwind()
.options({
processCssUrls: false
})
if (isDevelopment) {
mix.sourceMaps()
}
mix.webpackConfig({
mode: isDevelopment ? 'development' : 'production',
context: __dirname,
node: {
__filename: true,
__dirname: true,
},
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: ['@babel/preset-react'],
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean),
},
},
],
},
],
},
plugins: [
isDevelopment && new webpack.HotModuleReplacementPlugin(),
isDevelopment && new ReactRefreshWebpackPlugin(),
new webpack.ProvidePlugin({
React: 'react',
}),
].filter(Boolean),
})

- add .gitignore

# other settings...
mix-manifest.json
hot
public/js/*
public/css/*
public/**/*_js*

- Configure Tailwind

yarn add -D tailwindcss@npm:@tailwindcss/postcss7-compat @tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9 sass-loader@8.* sass postcss@^8.1;
mkdir -p resources/assets/scss && touch resources/assets/scss/index.scss;
npx tailwindcss init

tailwind.config.js

module.exports = {
purge: ['./resources/client/**/*.{js,jsx,ts,tsx}', './resources/views/**/*.edge'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}

resources/assets/scss/index.scss 

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

- Create Client React App

yarn add react react-dom;
mkdir -p resources/client && touch resources/client/index.js resources/client/App.js;

resources/client/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);

resources/client/App.js

import React from 'react'
export default function App() {
return (
<div>
Hello World!
</div>
)
}

using index.js in resources/views/index.edge 

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/index.css">
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/js/index.js"></script>
</body>
</html>

package.json

"start": "node build/server.js",
"server": "node ace serve --watch",
"client": "node ace mix:watch",
"build": "yarn client:build && yarn server:build",
"server:build": "node ace build --production",
"client:build": "node ace mix:build --production",
"dev": "concurrently \"yarn server\" \"yarn client\"",

=> watch client: yarn client

Reference: guide

Thank you.  

Golang Advanced Interview Q&A