whatisthis?
220315 [TIL] Today I Learned ๐ฏ React.js - (2) ๋ณธ๋ฌธ
React.js
Day 03 React Hooks + WebPack
๐พ PART 1
220315 [TIL] Today I Learned ๐ฏ React.js - (1)
React.js Day 03 React Hooks + WebPack 1 / React Hooks ๋ฆฌ์กํธ์์ ์ถ์ฒํ๋ ๊ฒ = Hooks์ ์ฌ์ฉ. Class Component๋ฅผ ์์ ํ๊ณ , ํจ์ํ ํ๋ก๊ทธ๋๋ฐ์ ์ํ Hooks๋ฅผ ๊ถ๊ณ ํจ. ํด๋์ค ์ปดํฌ๋ํธ class Button extends..
mywebproject.tistory.com
* ์ง๊ธ๊น์ง์ ์ฝ๋
๐ webpack.config.js
const path = require("path");
module.exports = {
name: "wordrelay-setting",
mode: "development", // ์ค์๋น์ค์์ 'production'์ผ๋ก
devtool: "eval", // ๋น ๋ฅด๊ฒ
resolve: {
extensions: [".js", ".jsx"],
},
entry: {
app: ["./client.jsx", "WordRealy.jsx"],
},
output: {
path: path.join(__dirname, "dist"), //__dirname์ ํ์ฌํด๋๊ฒฝ๋ก
filename: "app.js",
},
};
์ฐธ๊ณ - devtool์ ๊ฐ๋ฐ์ ์ฉ์ดํ๊ฒ ํ๊ธฐ ์ํด ์์ค๋งต์ ์ ๊ณตํ๋ ์ต์ .
๋๋ ํ๋ ํ์ผ์ ์ค๋ฅ๊ฐ ์ด๋์์ ๋ฌ๋์ง ํ์ธ์ด ํ๋๋ฏ๋ก
์์ค๋งต์ ํตํด ํ์ธํ ์ ์๊ฒ ํด์ค๋ค.
๐ ์๋ ๊ธ์ ์ฐธ๊ณ ํด์ ํ์ด๋ณด์.
(Webpack) devtool ์ต์ ํผํฌ๋จผ์ค
๋ชฉ์ฐจ ๋ค์ด๊ฐ๊ธฐ์ ์์ ์์ค๋งต devtool ๋ง์น๋ฉฐ… ๋ค์ด๊ฐ๊ธฐ์ ์์์ด ํฌ์คํธ์์๋ ์นํฉ์ ๋ํ ๊ธฐ์ด ๋ด์ฉ์ ์ค๋ช ํ์ง ์๋๋ค.์นํฉ์ ๋ชจ๋ฅด๋ ์ฌ๋์ ์ดํฌ์ ๋ค๋ก๊ฐ๊ธฐ๋ฅผ ๋๋ฅด๋ ๊ฑธ ๊ถ์ฅํ๋ค.
perfectacle.github.io
npx webpack
์ปค๋งจ๋๋ผ์ธ์ ๋ช ๋ น์ด๋ฅผ ์น๋ ค๋ฉด, ๋ฑ๋ก์ ํด์ค์ผํ๋ค.
๋ฐฉ๋ฒ 1 / ๋ช ๋ น์ด๋ก ๋ฑ๋ก
๋ฐฉ๋ฒ 2 / package.json์ "scripts" : {} ์์ ์ ๊ธฐ
"scripts": {
"dev": "webpack"
},
๋ฐฉ๋ฒ 3 / $npx webpack ์ด๋ผ๊ณ ์ ๋ ฅ
- ๐โ๏ธ ์ด ๋ฐฉ๋ฒ์ผ๋ก ํด๋ณด์!
Module parse failed: Unexpected token (6:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| const WordRelay = require("./WordRelay");
|
> ReactDom.render(<WordRelay />, document.querySelector("#root"));
|
๊ทธ๋ฌ๋ฉด ์ด๋ฐ์์ผ๋ก ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
๋์ถฉ ํด์ํ์๋ฉด,
" Module์ ์ฐพ๋๊ฑธ ์คํจํ๋ค
-> ์ด file ํ์ ์ ๋ค๋ฃจ๋ ค๋ฉด, ์ ์ ํ loder๊ฐ ํ์ํ๋ค. "
>> jsx๋ฅผ ํด์ํ ์ ์๋ ๋ฐ๋ฒจ ์ ํ ์ ํ์ง ์์๊ธฐ ๋๋ฌธ์ ์๋ฌ๊ฐ ๋๊ฒ์.
๋ฐ๋ฒจ์ ์ค์นํ๋ค๊ณ ๋ฐ๋ก JSX๋ฅผ ์ธ ์ ์๋? >> โ
๋ฐ๋ฒจ ๋ด์์๋ ์ค์ ์ ํด์ค์ผ ํ๋ค.
1 / ํ์ํ ๋ฐ๋ฒจ ์ค์นํ๊ธฐ
$ npm i -D @babel/core @babel/preset-env @babel/preset-react babel-loader
- core : ๊ธฐ๋ณธ์ ์ธ ๊ฒ ํฌํจ
- preset-env : ๋ธ๋ผ์ฐ์ ์ ๋ง๊ฒ ์ต์ ๋ฌธ๋ฒ์ ์๋ ๋ฌธ๋ฒ์ผ๋ก ๋ฐ๊ฟ์ค
- preset-react : JSX๋ฅผ ์ธ ์ ์๊ฒ
- babel-loader : ๋ฐ๋ฒจ๊ณผ ์นํฉ ์ฐ๊ฒฐ
package.json ํ์ธ"devDependencies": { "@babel/core": "^7.17.7", "@babel/plugin-proposal-class-properties": "^7.16.7", "@babel/preset-env": "^7.16.11", "@babel/preset-react": "^7.16.7", "babel-loader": "^8.2.3", // ์๋ต }
2 / webpack.config.js ์์
module ๋ผ๋ ํ๋กํผํฐ ์ถ๊ฐ ํ,
rules ๋ผ๋ ๋ฐฐ์ด์์ ๋ค์๊ณผ ๊ฐ์ด ์ ์ด์ค.module: { rules: [ { test: /\.jsx?/, // ์ ๊ทํํ์ -js๋ jsx loader: "babal-loader", options: { presets: ["@babel/preset-env", "@babel/preset-react"], }, }, ], },
test - ํ์ผ์ด js๋ jsx์ธ์ง ํ ์คํธํ๋ผ๋ ์๋ฏธ.
์ ๊ทํํ์์ผ๋ก ์์ฑํ๋๋ฐ, ์๋ ๋ฌธ์ ์ฐธ๊ณ .
loader - babel-loader์ ์ฐ๋ผ๋ ์๋ฏธ.
(cr: babelsjs.io)
๐โ๏ธ Using a Preset
Within a Babel config, if the preset is on npm, you can pass in the name of the preset and
Babel will check that it's installed in node_modules already.
This is added to the presets config option, which takes an array.
3 / ๋ค์ํ๋ฒ $ npx webpack ์ ๋ ฅํ๊ธฐ
๋๋์ด ์ ์์ ์ผ๋ก built ์๋ฃ ๐
๐ ์ ๊ทํํ์ ์ด๋?
์ ๊ท ํํ์ - JavaScript | MDN
์ ๊ท ํํ์, ๋๋ ์ ๊ท์์ ๋ฌธ์์ด์์ ํน์ ๋ฌธ์ ์กฐํฉ์ ์ฐพ๊ธฐ ์ํ ํจํด์ ๋๋ค. JavaScript์์๋ ์ ๊ท ํํ์๋ ๊ฐ์ฒด๋ก์, RegExp์ exec()์ test() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. String์ match(), matchA
developer.mozilla.org
/ / ์์ ์์ฑ.
\.๋ ์ด์ค์ผ์ดํ = "."์ ์๋ฏธํจ.
๐ป ์์
์ ํ๋ฒํธ๋ฅผ ์
๋ ฅ ํ "ํ์ธ" ๋ฒํผ์ ๋๋ฅด์ธ์.
###-####-####์ ํ์์ผ๋ก ์
๋ ฅํ์ธ์.
const form = document.querySelector('#form')
const input = document.querySelector('#phone')
const output = document.querySelector('#output')
const re = /^(?:\d{3}|\(\d{3}\))([-\/\.])\d{4}\1\d{4}$/
function testInfo(phoneInput) {
const ok = re.exec(phoneInput.value)
if (!ok) {
output.textContent = `ํ์์ ๋ง์ง ์๋ ์ ํ๋ฒํธ์
๋๋ค. (${phoneInput.value})`
} else {
output.textContent = `๊ฐ์ฌํฉ๋๋ค. ์ ํ๋ฒํธ๋ ${ok[0]} ์
๋๋ค.`
}
}
form.addEventListener('submit', (event) => {
event.preventDefault()
testInfo(input)
})
์นํฉ์ด ์ ๋น๋๋์๋์ง ํ ์คํธ ํ๊ธฐ ์ํด
WordRelay.jsx ํ์ผ์ ๊ณ ์ณ๋ณด์.
const React = require("react");
const { Component } = React;
class WordRelay extends Component {
state = {
text: "Hello Webpack",
};
render() {
return <h1>{this.state.text}</h1>;
}
}
module.exports = WordRelay;
+) ์ฐธ๊ณ ๋ก, app.js ๋ณด๋ฉด ์ฝ๋๊ฐ ์๋์ผ๋ก ์์ฑ๋์ด์์.
- ์นํฉ์ด client.jsx๋ WordRelay.jsx๋ฅผ ํฉ์ณ์ app.js ์์ ๋ด์ฉ์ ๋ง๋ ๊ฒ์!
์์ฉ ์์
- ์ง๋๋ฒ ์์ ์๋ ๊ตฌ๊ตฌ๋จ ๊ฒ์์ ์นํฉ์ผ๋ก ๋น๋ํด๋ณด์!
์ง๊ธ๊น์ง์ ๊ณผ์ ๋๋ก
1. npm init
2. npm i react, react-dom
3. npm i -D webpack webpack-cli
4. npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties
5. webpack.config.js ์ค์ ํ๊ธฐ
- name / mode / devtool
- resolve - extensions: .js, .jsx
- entry
app: "./client"
- module
test
loader
options - presets
- output
- path: path.join(__dirname, "dist")
- filename : 'app.js'
6. GuGuDan.jsx ์์ฑ
- ์ง๋๋ฒ์ ์์ฑํ๋ ๊ฒ ํ์ฅ์๋ช ๋ง ๋ฐ๊พธ๊ณ ,
- react require๋ก ๊ฐ์ ธ์ค๊ณ ,
- module.exports = GuGuDan
+) ์ฌ๊ธฐ์ React.useState์ React.useRef๋ฅผ ์ฌ์ฉํ๋ฏ๋ก
๊ตฌ์กฐ๋ถํด ๋ฌธ๋ฒ์ผ๋ก ๋์ ์ ์ธํด์ค.
>> ์๋ ๋ณธ๋ฌธ์์
const [first, setFirst] = React.useState(''); ์ด๋ฐ์์ผ๋ก ์จ์ฃผ๋๊ฑธ
const [first, setFirst] = useState(''); ๋ผ๊ณ ๋ง ํด์ค๋ ๋๋ค.
const React = require("react");
const { useState, useRef } = React;
const GuGuDan = () => {
const [first, setFirst] = useState(Math.ceil(Math.random() * 9));
const [second, setSecond] = useState(Math.ceil(Math.random() * 9));
const [value, setValue] = useState("");
const [result, setResult] = useState("");
let inputRef = useRef(null);
const onFormSubmit = e => {
e.preventDefault();
if (parseInt(value) === first * second) {
setResult(prevResult => {
return "์ ๋ต์
๋๋ค! " + value;
});
setFirst(Math.ceil(Math.random() * 9));
setSecond(Math.ceil(Math.random() * 9));
setValue("");
inputRef.current.focus();
} else {
setResult("โ ์ค๋ต์
๋๋ค");
setValue("");
inputRef.current.focus();
}
};
const onInputChange = e => {
setValue(e.target.value);
};
return (
<>
<h1>๐ฏ๊ตฌ๊ตฌ๋จ ๊ฒ์๐ฏ</h1>
<div>
๐ {first} ๊ณฑํ๊ธฐ {second} ๋?
</div>
<form onSubmit={onFormSubmit}>
<input
ref={inputRef}
type="number"
required
placeholder="์ ๋ต ์
๋ ฅ"
value={value}
onChange={onInputChange}
/>
<button type="submit">์
๋ ฅ</button>
</form>
<div>{result}</div>
</>
);
};
module.exports = GuGuDan;
7. ์ด์ $npx webpack์ด๋ผ๊ณ ์น๊ฑฐ๋, package.json์์ scripts ๋ถ๋ถ์
"scripts": {
"dev": "webpack"
},
์์๊ฐ์ด ์ ์ธํ์ผ๋ฏ๋ก,
$npm run dev ๋ผ๊ณ ์ณ๋ ๋๋ค.
์ฐธ๊ณ - ๋ ๋น์ฐํ ./dist/app.js๋ฅผ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ณ (๋นํ์ผ)
npx webpack์ ํ๋๋ฐ, ๊ทธ๋ฅ ์๋์ผ๋ก ์์ฑ๋๋ค.
๐ ๋๋ ํฐ๋ฆฌ ๊ตฌ์กฐ
index.html์ ๋ฐ๋์ ์์ด์ผํ๊ณ
client.jsx๋ ์ํธ๋ฆฌ์ฉ. (entry๋ ๋ณดํต client.jsx๋ก)
๊ทธ๋ฆฌ๊ณ ./dist/app.js๋ output์ฉ.
๋ชจ๋ jsxํ์ผ์ ํฉ์ณ์ app.js๋ฅผ ๋ง๋ค๊ณ ,
๊ทธ๊ฑธ index.html์ script:src๋ก ์ฐ๊ฒฐํ์.
์ฐธ๊ณ
๐ง webpack.config.js
module: {
rules: [
{
test: /\.jsx?/,
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"],
},
},
],
},
์ด๋ถ๋ถ์ ๋ณด๋ฉด,
loader๊ฐ babel-loader์ด๊ณ , ๊ทธ์ ํด๋นํ๋ options๊ฐ presets ๋ถ๋ถ์ ํด๋นํ๋ค.
๋ง์ฝ, @babel/preset-env์ ๋ํ ์ค์ ์ด ๋ ํ์ํ๋ค๋ฉด??
** preset์ด๋, ํ๋ฌ๊ทธ์ธ๋ค์ ๋ชจ์์ด๋ค.
options: {
presets: [
[
"@babel/preset-env", {
targets: {
browsers: ["last 2 chrome versions"],
},
debug: true,
],
"@babel/preset-react",
],
},
์ด๋ฐ์์ผ๋ก ํด๋น preset์ ๋ฐฐ์ด๋ก ๊ฐ์ธ์ฃผ๊ณ ,
์ฒซ๋ฒ์งธ ์์๋ก๋ ์ด๋ฆ์ ์ ์ด์ฃผ๊ณ
๋๋ฒ์งธ ์์๋ก option์ ์ ์ด์ฃผ๋ฉด ๋๋ค.
์ฌ๊ธฐ์๋ preset-env์ ์ต์ ์ค ํ๋๋ก, target - browser์ ์ด์ฉํ๋ค.
(ํฌ๋กฌ์ ์ต์ 2๋ฒ์ ๊น์ง๋ง ํธํ๋๋๋ก)
๐ป [์ฐธ๊ณ ] ๋ธ๋ผ์ฐ์ ๋ฆฌ์คํธ (target)
GitHub - browserslist/browserslist: ๐ฆ Share target browsers between different front-end tools, like Autoprefixer, Stylelint a
๐ฆ Share target browsers between different front-end tools, like Autoprefixer, Stylelint and babel-preset-env - GitHub - browserslist/browserslist: ๐ฆ Share target browsers between different front-en...
github.com
์ถ๊ฐ๋ก, plugins๋
module์ option์ preset๊ณผ ํจ๊ป ์ผ์๋๋ฐ,
plugins: [new webpack.LoaderOptionsPlugin({ debug: true })],
์ด๋ฐ์์ผ๋ก ๋จ๋ ์ผ๋ก ์จ๋ ๋๋ค.
module.exports = {
mode: "development", // ์ค์๋น์ค์์ 'production'์ผ๋ก
devtool: "eval", // ๋น ๋ฅด๊ฒ
resolve: {
extensions: [".js", ".jsx"],
},
entry: {
app: ["./client"],
},
module: {
rules: [
{
// ์๋ต
},
plugins: [new webpack.LoaderOptionsPlugin({ debug: true })], // ๐๐ ์ด ์์น์
output: {
path: path.join(__dirname, "dist"),
filename: "app.js",
},
};
- ์ฐธ๊ณ ๋ก, webpack์ LoaderOptions์ plugin์ ์ ๋ถ debug๋ฅผ true๋ฅผ ์ฃผ๋๊ฒ์.
const { webpack } = require("webpack");
+)
์๋์ผ๋ก ์ด๋ ๊ฒ webpack์ ๋ถ๋ฌ์ค๋ ์ฝ๋๊ฐ ์์ฑ๋๋ค.
(new webpack ๋ถ๋ถ ์ฃผ๋ชฉ)
* ์ง๊ธ๊น์ง์ ์ฝ๋
๐ webpack.config.js
const path = require("path");
const { webpack } = require("webpack");
module.exports = {
mode: "development", // ์ค์๋น์ค์์ 'production'์ผ๋ก
devtool: "eval", // ๋น ๋ฅด๊ฒ
resolve: {
extensions: [".js", ".jsx"],
},
entry: {
app: ["./client"],
},
module: {
rules: [
{
test: /\.jsx?/,
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
targets: {
browsers: ["last 2 chrome versions"],
},
debug: true,
},
],
"@babel/preset-react",
],
},
},
],
},
output: {
path: path.join(__dirname, "dist"),
filename: "app.js",
},
};
์ฐธ๊ณ - LoaderOptionsPlugin ์ด๋ถ๋ถ์ด ์๋ฌ๊ฐ ๋์
(์๋ง ์นํฉ ๋ฒ์ ํธํ์ฑ ๋ฌธ์ ์ธ๋ฏ)
๊ทธ๋ฅ ๋นผ๋ฒ๋ฆฌ๋ผ๊ณ ํด์ ๋บ๋ค.
+)
$ npm run dev ํด๋ณด๋ฉด ์ด๋ฐ์์ผ๋ก ๋ฌ๋ค
@babel/preset-env: `DEBUG` option
Using targets:
{
"chrome": "98"
}
Webpack ๊ณต์ Doc.
Concepts | webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
webpack.js.org
์นํฉ์ด ๊ฐ์กฐํ ๊ฐ๋ ์ ํฌ๊ฒ ๋ค์ฏ๊ฐ์ง.
- entry
- output
- loaders
- plugins
- mode
โ ์นํฉ ์ค์ ์์ฑํ ๋ TIP
entry - module - plugins - output ์์ผ๋ก ์์ฑํ๋ฉด ์ฌ์.
(ํ๋ฆ์ ๋ฐ๋ผ์)
entry์ ์๋ ํ์ผ์ module ์ ์ฉํ๊ณ , plugin๋ ์ถ๊ฐ์ ์ผ๋ก ์ ์ฉํ๊ณ
output์ผ๋ก ๋์ด.
'WEB STUDY > REACT' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
220317 [TIL] Today I Learned ๐ฏ React.js (0) | 2022.03.17 |
---|---|
220316 [TIL] Today I Learned ๐ฏ React.js (0) | 2022.03.16 |
220315 [TIL] Today I Learned ๐ฏ React.js - (1) (0) | 2022.03.15 |
220314 [TIL] Today I Learned ๐ฏ React.js (0) | 2022.03.14 |
220313 [TIL] Today I Learned ๐ฏ React.js (0) | 2022.03.13 |