Leyenda
Cuando naci贸 el proyecto, a todos les gust贸. Una hoja de papel en blanco y todos la miraban con expectaci贸n e imaginaban qu茅 perspectivas se abrir铆an, qu茅 problemas se resolver铆an.
El arquitecto puso el primer bloque en el papel. Hubo maldiciones por detr谩s. Estos son los desarrolladores, argumentando: Cu谩l es la mejor manera de iniciar un nuevo servicio y qu茅 motor de arranque elegir.
. Proof Of Concept, Minimal Valuable Product, . .
, . Team Lead WebPack , .
2020 - WebPack.
, create-react-app.
. .
loader's , 95% , . . devtool
devtools
. WebPack. TypeScript.
, backend frontend.
C FE . FE Hello World!
. BE node
, webpack
.
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
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.
TS - . . , micro-frontend c ModuleFederationPlugin
, webpack - , TS .
PD. Me gustar铆a saber si est谩 interesado en configurar el desarrollo a trav茅s de la implementaci贸n en Docker (para VSCode y JetBrains)