Para começar um projeto do zero, simples, usando HTML, CSS, TypeScript e ESBuild.
Precisa fazer as seguintes etapas:
- Criar o diretório com o nome do seu projeto
- Criar o package.json
- Criar o tsconfig.json
- Instalar as dependências
- esbuild
- esbuild-serve
- typescript
- prettier
- Criar o diretório src
- Escrever o TypeScript inicial dentro de
src
- Criar o diretório public/styles
- Escrever o HTML inicial dentro de
public
- Escrever o CSS inicial dentro de
public/styles
- Criar a configuração do ESBuild
- Criar a configuração do prettier
- Adicionar
"type": "module"
aopackage.json
- Adicionar o script de build ao
package.json
- Adicionar o script de start ao
package.json
- Executar o
npm start
Ou então compactar tudo isso em um script bash e usa-lo da seguinte forma
./create-project.sh meu-projeto
Segue o código do script
#!/bin/bash | |
# Para usar, dê permissão de execução ao script | |
# usando o comando: chmod +x create-project.sh | |
# e então execute: ./create-project.sh projeto | |
mkdir $1 | |
cd $1 | |
npm init -y | |
echo '{ | |
"compilerOptions": { | |
"target": "es5", | |
"lib": [ | |
"es2020", | |
"dom", | |
"dom.iterable" | |
], | |
"experimentalDecorators": true, | |
"emitDecoratorMetadata": true, | |
"module": "commonjs", | |
"esModuleInterop": true, | |
"forceConsistentCasingInFileNames": true, | |
"strict": false, | |
"skipLibCheck": true | |
} | |
}' > tsconfig.json | |
npm i -D esbuild esbuild-serve typescript@latest prettier | |
mkdir src | |
echo "document.addEventListener('DOMContentLoaded', () => { | |
const form = document.querySelector('form') | |
if (form) { | |
const button = form.querySelector('button') | |
if (button) button.disabled = true | |
form.onchange = () => { | |
const valid = !form.checkValidity() | |
if (button) button.disabled = valid | |
} | |
form.onsubmit = (ev) => { | |
ev.preventDefault() | |
const data = new FormData(form) | |
const values = Object.fromEntries(data.entries()) | |
console.log(values) | |
} | |
} | |
}) | |
" > src/main.ts | |
mkdir -p public/styles | |
echo '<!DOCTYPE html> | |
<html lang="pt-br"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<link rel="preconnect" href="https://fonts.googleapis.com" /> | |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
<link | |
href="https://fonts.googleapis.com/css2?family=Fira+Sans:wght@400;500&display=swap" | |
rel="stylesheet" | |
/> | |
<link rel="stylesheet" href="styles/main.css" /> | |
<script src="main.js" defer></script> | |
<title>Página da Web</title> | |
</head> | |
<body> | |
<header> | |
<h1>'$1'</h1> | |
</header> | |
<main> | |
<article> | |
<h2>Artigo sobre JavaScript</h2> | |
<p> | |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sin | |
laboramus, quis est, qui alienae modum statuat industriae? Traditur, | |
inquit, ab Epicuro ratio neglegendi doloris. Duo Reges: constructio | |
interrete. Te enim iudicem aequum puto, modo quae dicat ille bene | |
noris. Quamquam id quidem licebit iis existimare, qui legerint. Sed | |
quid sentiat, non videtis. Duo enim genera quae erant, fecit tria. | |
Quodsi ipsam honestatem undique pertectam atque absolutam. Odium autem | |
et invidiam facile vitabis. Consequens enim est et post oritur, ut | |
dixi. | |
</p> | |
<pre><code>document.addEventListener("DOMContentLoaded", () => { | |
const form = document.querySelector("form") | |
if (form) { | |
const button = form.querySelector("button") | |
if (button) button.disabled = true | |
form.onchange = () => { | |
const valid = !form.checkValidity() | |
if (button) button.disabled = valid | |
} | |
form.onsubmit = (ev) => { | |
ev.preventDefault() | |
const data = new FormData(form) | |
const values = Object.fromEntries(data.entries()) | |
console.log(values) | |
} | |
} | |
})</code></pre> | |
</article> | |
<form> | |
<section> | |
<label for="name">Nome</label> | |
<input | |
id="name" | |
type="text" | |
autofocus | |
autocomplete="given-name" | |
name="name" | |
required | |
/> | |
<output>Obrigatório</output> | |
</section> | |
<section> | |
<label for="email">E-mail</label> | |
<input | |
id="email" | |
type="email" | |
name="email" | |
autocomplete="email" | |
required | |
/> | |
<output>Email inválido</output> | |
</section> | |
<section> | |
<label for="password">Senha</label> | |
<input | |
id="password" | |
type="password" | |
name="password" | |
autocomplete="new-password" | |
minlength="6" | |
required | |
/> | |
<output>Mínimo de 6 caracteres</output> | |
</section> | |
<section> | |
<label> <input type="checkbox" name="terms" /> Li e concordo com os termos </label> | |
</section> | |
<hr /> | |
<button>Enviar</button> | |
</form> | |
</main> | |
<footer>© 2021</footer> | |
</body> | |
</html> | |
' > public/index.html | |
echo ':root { | |
/* Palette generated by Material Palette | |
materialpalette.com/deep-purple/cyan */ | |
--dark-primary-color: #512da8; | |
--default-primary-color: #673ab7; | |
--light-primary-color: #d1c4e9; | |
--text-primary-color: #ffffff; | |
--accent-color: #00bcd4; | |
--primary-text-color: #212121; | |
--secondary-text-color: #757575; | |
--divider-color: #bdbdbd; | |
--warn-color: #eb3535; | |
--default-font-family: "Fira Sans", sans-serif; | |
--default-element-margin: 6px; | |
--default-element-padding: 8px; | |
--default-block-padding: 10px; | |
--default-border-width: 2px; | |
--border-radius-xs: 2px; | |
--border-radius-sm: 4px; | |
--border-radius-md: 8px; | |
--border-radius-lg: 12px; | |
} | |
html, | |
body { | |
height: 100%; | |
} | |
body { | |
margin: 0; | |
display: flex; | |
flex-direction: column; | |
accent-color: var(--accent-color); | |
color: var(--primary-text-color); | |
font-family: var(--default-font-family); | |
} | |
main { | |
flex: 1; | |
padding: var(--default-block-padding); | |
} | |
header, | |
footer { | |
color: var(--text-primary-color); | |
padding: var(--default-block-padding); | |
background-color: var(--dark-primary-color); | |
} | |
button { | |
padding: var(--default-element-padding) | |
calc(var(--default-element-padding) * 2); | |
background-color: var(--default-primary-color); | |
border-radius: var(--border-radius-sm); | |
color: var(--text-primary-color); | |
border: 0; | |
} | |
button:disabled { | |
background-color: var(--light-primary-color); | |
} | |
button.accent { | |
background-color: var(--accent-color); | |
} | |
form section output { | |
visibility: hidden; | |
} | |
form.invalid input:invalid, | |
form section input:invalid:focus + output { | |
visibility: visible; | |
} | |
form section output { | |
color: var(--warn-color); | |
} | |
form section { | |
display: flex; | |
flex-direction: column; | |
margin-top: var(--default-element-margin); | |
margin-bottom: var(--default-element-margin); | |
} | |
input { | |
border-radius: var(--border-radius-sm); | |
padding: var(--default-element-padding); | |
border: var(--default-border-width) solid var(--dark-primary-color); | |
} | |
input[type="checkbox"] { | |
transform: scale(1.2); | |
} | |
pre { | |
padding: var(--default-block-padding); | |
background-color: var(--primary-text-color); | |
} | |
code { | |
font-size: 16px; | |
color: var(--light-primary-color); | |
} | |
' > public/styles/main.css | |
echo 'import esbuildServe from "esbuild-serve"; | |
esbuildServe( | |
{ | |
logLevel: "info", | |
entryPoints: ["src/main.ts"], | |
bundle: true, | |
outfile: "public/main.js", | |
sourcemap: true, | |
}, | |
{ root: "public" } | |
);' > esbuild.config.js | |
echo '{ | |
"semi": false, | |
"singleQuote": true | |
}' > .prettierrc | |
npx json -I -f package.json -e "this.type = 'module';" | |
npx json -I -f package.json -e "this.scripts.build = 'node esbuild.config.js';" | |
npx json -I -f package.json -e "this.scripts.start = 'node esbuild.config.js -w';" | |
npm start |
Ele é extremamente simples e resolve o propósito com excelência.
Espero ter ajudado, até a próxima.
[]s
Top comments (0)