
Légende
Quand le projet est né, tout le monde l'a aimé. Une feuille de papier blanc et tout le monde l'a regardée avec attente et imaginé quelles perspectives s'ouvriraient, quels problèmes seraient résolus.
L'architecte a mis le premier bloc sur le papier. Il y avait des jurons par derrière. Ce sont les développeurs qui se disputent: Comment démarrer au mieux un nouveau service et quel démarreur choisir.
. Proof Of Concept, Minimal Valuable Product, . .
, . Team Lead WebPack , .
2020 - WebPack.
, create-react-app.
. .
loader's , 95% , . . devtool
devtools
. WebPack. TypeScript.
, WebPack : .
, backend frontend.
C FE . FE Hello World!
. BE node
, webpack
.
GitHub:
c
- server webapp
~/projectfolder/ # --
yarn init
/apps #
/server # backend --
yarn init
/src #
( BE)
/webapp # frontend --
yarn init
/src #
( FE)
/utils #
~/project_folder
yarn add -D @types/node @types/webpack concurrently cross-env nodemon ts-loader ts-node typescript webpack webpack-cli
/apps/server
-
/apps/web_app
html-webpack-plugin
5 WebPack 5 . beta .
cd apps/web_app
yarn add -D html-webpack-plugin@5
TypeScript
, server, runner - :
, node . : https://node.green
apps/server/tsconfig.json
, webpack .
, 2020, ES6 Internet Explorer 11. : https://caniuse.com
: apps/web_app/tsconfig.json
runner , . TS, ts-node
webpack.
tsconfig.json
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
}
webpack typescript
, . () node, ..\..\secret
.
apps/server/src/index.ts
import { resolve, normalize, join } from 'path'
import { createServer, RequestListener} from 'http'
import { readFile } from 'fs'
const webAppBasePath = '../web_app'; // build ( dist)
const handleWebApp: RequestListener = (req, res) => {
const resolvedBase = resolve(__dirname ,webAppBasePath);
const safeSuffix = normalize(req.url || '')
.replace(/^(\.\.[\/\\])+/, '');
const fileLocation = join(resolvedBase, safeSuffix);
readFile(fileLocation, function(err, data) {
if (err) {
res.writeHead(404, 'Not Found');
res.write('404: File Not Found!');
return res.end();
}
res.statusCode = 200;
res.write(data);
return res.end();
});
};
const httpServer = createServer(handleWebApp)
httpServer.listen("5000", () => {
console.info('Listen on 5000 port')
})
Frontend
Web . document.body
<div id="root">Hello world!</div>
apps/web_app/src/index.ts
const rootNode = document.createElement('div')
rootNode.setAttribute('id', 'root')
rootNode.innerText = 'Hello World!'
document.body.appendChild(rootNode)
WebPack
webpack.
. TS, import {serverConfig} from "./apps/server/webpack.part";
- .
webpack.config.ts
import {serverConfig} from "./apps/server/webpack.part";
import {webAppConfig} from "./apps/web_app/webpack.part";
import {commonConfig} from "./webpack.common";
export default [
/** server **/ {...commonConfig, ...serverConfig},
/** web_app **/ {...commonConfig, ...webAppConfig},
]
.
. mode
resolve
. , const commonConfig: Configuration
, import {Configuration} from "webpack";
.
webpack.common.ts
import {Configuration, RuleSetRule} from "webpack";
import {isDev} from "./apps/_utils";
export const tsRuleBase: RuleSetRule = {
test: /\.ts$/i,
loader: 'ts-loader',
}
export const commonConfig: Configuration = {
mode: isDev ? 'development' : 'production',
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
},
}
TS const tsRuleBase: RuleSetRule
, import {RuleSetRule} from "webpack";
.
isDev
isDev = process.env.NODE_ENV === 'development'
FE BE
webpack, import {Configuration, RuleSetRule, WebpackPluginInstance} from "webpack";
WatchIgnorePlugin
- .
apps/server/webpack.part.ts
import {Configuration, RuleSetRule, WatchIgnorePlugin, WebpackPluginInstance} from "webpack";
import {join} from "path";
import {tsRuleBase} from "../../webpack.common";
const serverPlugins: WebpackPluginInstance[] = [
new WatchIgnorePlugin({
paths: [join(__dirname, '..', 'apps', 'web_app')]
})
]
const tsRuleServer: RuleSetRule = {
...tsRuleBase,
options: {
configFile: join(__dirname, 'tsconfig.json')
}
}
export const serverConfig: Configuration = {
entry: join(__dirname, 'src', 'index.ts'),
output: {
path: join(__dirname, '..', '..', 'dist', 'server'),
filename: 'server.js'
},
target: 'node',
plugins: serverPlugins,
module: {
rules: [tsRuleServer]
}
}
apps/web_app/webpack.part.ts
import {Configuration, RuleSetRule, WatchIgnorePlugin, WebpackPluginInstance} from "webpack";
import HtmlWebpackPlugin from "html-webpack-plugin";
import {join} from "path";
import {tsRuleBase} from "../../webpack.common";
const webAppPlugins: WebpackPluginInstance[] = [
new HtmlWebpackPlugin(),
new WatchIgnorePlugin({
paths: [join(__dirname, '..', 'apps', 'server')]
})
]
const tsRuleWebApp: RuleSetRule = {
...tsRuleBase,
options: {
configFile: join(__dirname, 'tsconfig.json')
}
}
export const webAppConfig: Configuration = {
entry: join(__dirname, 'src', 'index.ts'),
output: {
path: join(__dirname, '..', '..', 'dist', 'web_app'),
filename: 'bundle.js'
},
target: 'web',
plugins: webAppPlugins,
module: {
rules: [tsRuleWebApp]
}
}
- ts-loader
, configFile: join(__dirname, 'tsconfig.json')
. __dirname
. backend EcmaScript esnext, frontend es6.
"UNLICENSE". Github: .
TS - . . , micro-frontend c ModuleFederationPlugin
, webpack - , TS .
PS. Je voudrais savoir si vous êtes intéressé par la mise en place du développement via le déploiement dans docker (pour VSCode et JetBrains)