Next.js: webpack์—์„œ .jsx ํ™•์žฅ์ž ํ•ด๊ฒฐ

์— ๋งŒ๋“  2016๋…„ 11์›” 04์ผ  ยท  34์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: vercel/next.js

React ๊ตฌ์„ฑ ์š”์†Œ์—๋Š” .jsx ํŒŒ์ผ ํ™•์žฅ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด webpack์— .jsx ํ™•์žฅ์ž๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ข‹์ง€ ์•Š์„๊นŒ์š”?

์ด๊ฒƒ์€ ๋˜ํ•œ ๊ตฌ๋ฌธ ๊ฐ•์กฐ ๋ฐ ๋ฆฐํŒ…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํŽธ์ง‘์ž์—๊ฒŒ๋„ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

.jsx ํ™•์žฅ ์ง€์›์„ ์œ„ํ•ด +1

๋ชจ๋“  34 ๋Œ“๊ธ€

ํฅ๋ฏธ๋กœ์šด. .jsx ๊ฐ€ ๊ถŒ์žฅ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ด๋ผ๋Š” ์ •๋ณด๋Š” ์–ด๋””์„œ ์–ป์œผ์…จ๋‚˜์š”? ๋‚˜๋Š” ๋น ๋ฅธ ๊ตฌ๊ธ€ ๊ฒ€์ƒ‰์„ํ–ˆ์ง€๋งŒ ์ด๊ฒƒ์— ๋Œ€ํ•œ ๊ณต์‹์ ์ธ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ๋‚ด Google foo๊ฐ€ ์ตœ๊ณ ๊ฐ€ ์•„๋‹˜์„ ์ธ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ์ €๋Š” ํŽธ์ง‘๊ธฐ์—์„œ ์ž๋™ ์–ธ์–ด ์„ ํƒ์„ ์œ„ํ•ด .jsx๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ JavaScript ํ”„๋กœ์ ํŠธ Linting์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋Š” airbnb ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ ์—์„œ.

@7s4r ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค . ์—์–ด๋น„์•ค๋น„ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๋ฅผ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๋˜ ๊ฒƒ์€ ํŽ˜์ด์Šค๋ถ์ด๋‚˜ babel์—์„œ ์ง์ ‘ ์˜จ ๋Œ“๊ธ€์ด์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—์–ด๋น„์•ค๋น„ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๊ฐ€ ์ข‹์€ ์ ์€ ํ™•์‹คํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋ฌธ์ œ์— ๋Œ€ํ•œ ์„ค๋ช…์—์„œ ์ด๋ฏธ ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ์„œ :+1: ์„ ์–ป์Šต๋‹ˆ๋‹ค. :).

.jsx ํ™•์žฅ์„ ์ง€์›ํ•˜๋Š” ๋ฐ ์œ ๋ฆฌํ•œ ๋˜ ๋‹ค๋ฅธ ์ ์€ ES6/ES2015๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•  ๋•Œ๋งˆ๋‹ค TypeScript๊ฐ€ ํ•ด๋‹น ํ™•์žฅ์œผ๋กœ ์ปดํŒŒ์ผ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

airbnb / eslint-plugin-react ์ด react/jsx-filename-extension ๊ทœ์น™์— ๋Œ€ํ•ด ๋ถˆํ‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์›นํŒฉ ๊ตฌ์„ฑ์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ https://github.com/zeit/next.js#customizing -webpack-config๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

next.config.js๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด๊ฐ€ ๋งํ•  ์ˆ˜ ์žˆ๋Š” ํ•œ, ์ด๊ฒƒ์€ ํ”„๋ ˆ์ž„์›Œํฌ( babel-loader , hot-self-accept-loader , react-hot-loader/webpack , emit-file-loader )์—์„œ ์ƒ์„ฑํ•œ 4๊ฐœ ์ด์ƒ์˜ ๋กœ๋”๋ฅผ ๋ฎ์–ด์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋ฌธ์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๋‚˜์œ ์ƒ๊ฐ์ด๋ผ๊ณ  ๋ถ€๋ฅด๋ฉฐ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ชฉ์ ์„ ๋ฌดํšจํ™”ํ•ฉ๋‹ˆ๋‹ค.

๊ณต์‹ ์ž…์žฅ์ด๋ผ๋ฉด ์ง€์ง€ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ์€๋ฐ, ์œ„์˜ ๋Œ“๊ธ€์ด ๊ทธ๋ ‡๋‹ค๊ณ  ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@AlteredConstants๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

module.exports = {
  webpack: (config, { dev }) => {
    config.resolve.extensions = ['', '.js', '.jsx'];
    return config;
  }
}

_ํ•˜์ง€๋งŒ_, ๋ฐฉ๊ธˆ ์‹œ๋„ํ•œ ๊ฒฐ๊ณผ ์ด โ€‹โ€‹์ ‘๊ทผ ๋ฐฉ์‹ ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค . ์ด์œ ๋ฅผ ์•Œ์•„๋‚ด๋ ค๋ฉด ํŒŒํ—ค์ณ ๋ด์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค.

@rossipedia, ๊ทธ๊ฒƒ์€ ๋‹จ์ง€ ํ™•์žฅ์ด ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐ€์ ธ ์˜ค๊ธฐ์—์„œ ์ œ์™ธ ๋  ๋•Œ ์›นํŒฉ์€ .jsx ํ™•์žฅํ•˜์—ฌ ๊ฐ€์ ธ์˜จ ๋ชจ๋“ˆ์„ ์ธ์‹ ํ•  ์ˆ˜ ์žˆ๋„๋ก import Foo from './Foo' ๋Œ€์‹  import Foo from './Foo.jsx' .

Webpack์ด ํ•ด๋‹น ๋ชจ๋“ˆ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋กœ๋”์˜ test ์†์„ฑ์— .jsx ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•ฝ๊ฐ„ ๋ฌด๊ฒ๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉฐ ์œ„์— ๋งํฌ๋œ ๋ฌธ์„œ์— ๋”ฐ๋ผ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋œ ์ผ€์ด์Šค๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž๋™ page/ ๊ฐ€์ ธ์˜ค๊ธฐ๊ฐ€ ์ด ๊ฒฝ์šฐ์—๋„ ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์‹ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. Webpack ํ”„๋กœ์„ธ์Šค ์™ธ๋ถ€์—์„œ ๋ฐ/๋˜๋Š” ๋ณ„๋„์˜ ์ง„์ž…์ ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ž…๋‹ˆ๊นŒ?

๋‹น์—ฐํžˆ ์ด ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ๋ชจ๋“ˆ ํ™•์ธ์€ ๋‹จ์ˆœํ•œ Webpack ๊ตฌ์„ฑ ์˜ต์…˜๋ณด๋‹ค ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ๋‚ด๊ฐ€ ํ‹€๋ฆฌ์ง€ ์•Š๋Š” ํ•œ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ์ฑ…์€ "ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•"๋ณด๋‹ค "์ˆ˜์ •๋˜์ง€ ์•Š์„ ๊ฒƒ"์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ €๋Š” ๋‹จ์ง€ ํŒ€์˜ ์ž…์žฅ์„ ๋ถ„๋ช…ํžˆ ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. @improuncciable , ๋” ๋งŽ์€ ํ†ต์ฐฐ๋ ฅ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ด๊ฒƒ์„ FAQ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

module.exports = {
  webpack: (config) => {
    config.resolve.extensions = ['.js', '.jsx'];
    config.module.rules.push(
      {test: /\.(js|jsx)$/, use: 'babel-loader'}
    );
    return config;
  }
}

@JF-Liu๋Š” ๋‚˜๋ฅผ ์œ„ํ•ด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Error: Cannot find module '../components/Page' ๋˜๋Š” Module build failed: Error: Couldn't find preset "stage-3" relative to directory "/Users/cla/Projects/with-mobx/node_modules/styled-jsx" ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

next.js 2-beta + mobx + airbnb ์„ค์ • ์‹œ๋„

๋‚ด๊ฐ€ ๋ญ”๊ฐ€๋ฅผ ๋†“์น˜๊ณ  ์žˆ๋Š” ๊ฑด ์•„๋‹๊นŒ? .babelrc ์ฝ˜ํ…์ธ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

pages ํ™•์žฅ์ž๋Š” .jsx ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

@foxhound87 ์˜ˆ, ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ €๋„ ํฌ๊ธฐํ•ฉ๋‹ˆ๋‹ค.

TypeScript 2.2๋Š” ์ด์ œ "jsx": "react-native" ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ .js ํŒŒ์ผ์„ ์ถœ๋ ฅํ•˜์ง€๋งŒ JSX๋„ ๋ณด์กดํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ์ฐธ์กฐ

์—ฌ๊ธฐ์— ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค :<, ์ด๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

์šฐ๋ฆฌ ํšŒ์‚ฌ ํ‘œ์ค€์€ jsx ๋งˆํฌ์—…์ด ํฌํ•จ๋œ ๋ชจ๋“  ํŒŒ์ผ์— .jsx ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ๋ฒ ์ดํฌ์˜คํ”„๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ ์ด ๋ฌธ์ œ์— ๋ถ€๋”ช์ณค์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€ ์›นํŒฉ ๊ตฌ์„ฑ์ด๋ฉฐ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ Next.js๊ฐ€ jsx ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

_ํŽธ์ง‘ํ•˜๋‹ค:_
์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด webpack ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์ž˜ ์ž‘๋™ํ•˜์ง€๋งŒ /pages/ ํŒŒ์ผ์€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋ผ์šฐํŒ…ํ•˜๋ ค๋ฉด .js ํ™•์žฅ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ์–ด๋ฆฌ์„์€ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€๊ทœ๋ชจ ํŒ€์€ ํ‘œ์ค€/๊ทœ์•ฝ์„ ์ค€์ˆ˜ํ•ด์•ผ ์ด ํ›Œ๋ฅญํ•œ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ฑ„ํƒ์ด ์ฐจ๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ  Next์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ฒƒ์ด ์ •๋ง ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„ ์šฐ๋ฆฌ๊ฐ€ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ž˜๋„ ์ง„์ „์ด ์žˆ๋Š”์ง€ ๋‹ค์‹œ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋Š” Webpack๊ณผ Babel๋ณด๋‹ค ํ›จ์”ฌ ๋” ๊นŠ์ด ํ™•์žฅ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ณณ์— ํ•˜๋“œ์ฝ”๋”ฉ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. :(

์ง€๊ธˆ๊นŒ์ง€ ๋‚ด๊ฐ€ ํ•œ ์œ ์ผํ•œ ๋…ธ๋ ฅ์€ server/resolve.js:34 ์— "jsx" ํ–‰์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋‚ด ํ”„๋กœ์ ํŠธ์˜ node_modules/next/dist/ ์•„๋ž˜์— ์žˆ๋Š” ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜์—ฌ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ˆ˜์ •ํ•˜๋ฉด ์ฝ˜์†”์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ฐธ๊ณ  ์ฝ˜์†”์ด ์ง€๊ธˆ ๋งํ•œ๋‹ค Building page: / ๊ฐ€ ์•„๋‹ˆ๋ผ, Client pings, but there's no entry for page: / .

 DONE  Compiled successfully in 12156ms                                                    8:34:44 PM

> Ready on http://localhost:3000
> Building page: /


 DONE  Compiled successfully in 10983ms                                                    8:34:58 PM

SyntaxError: Unexpected token m in JSON at position 0
    at JSON.parse (<anonymous>)
    at _callee$ (/Users/Jason/Repositories/radioapp/node_modules/next/dist/server/read-page.js:48:32)
    at tryCatch (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:64:40)
    at Generator.invoke [as _invoke] (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:299:22)
    at Generator.prototype.(anonymous function) [as next] (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:116:21)
    at step (/Users/Jason/Repositories/radioapp/node_modules/babel-runtime/helpers/asyncToGenerator.js:17:30)
    at /Users/Jason/Repositories/radioapp/node_modules/babel-runtime/helpers/asyncToGenerator.js:28:13

ํŽธ์ง‘ํ•˜๋‹ค:

.eslintrc ํŒŒ์ผ๋กœ server ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์ œ๋Š” ์‹ค์ œ๋กœ ๊ฒฌ๋”œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

{
  "parser": "espree",
  "parserOptions": {
    "ecmaVersion": 6,
  },

  "env": {
    "node": true
  },
}

๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋„์›€์ด ๋˜๋Š” ๊ฒฝ์šฐ ๋””๋ ‰ํ† ๋ฆฌ๋ณ„๋กœ ๋‹ค๋ฅธ ๋ฆฐํ„ฐ ์™€ Sublime ์„ค์ •์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Next.js ํŒŒ์ผ์ด ํฌํ•จ๋œ public ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ  ์ ์ ˆํ•œ .eslintrc ํŒŒ์ผ์„ ๊ฑฐ๊ธฐ์— ๋„ฃ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” babel-sublime ๋ฐ SublimeLinter-contrib-eslint ์™€ ํ•จ๊ป˜ Sublime์„ ์‚ฌ์šฉ

@jasonszhao ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ .jsx ์ง€์›์„ ์ง€์›ํ•  ๊ฐ€๋Šฅ์„ฑ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. .js ํ™•์žฅ์ž๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

@arunoda ์‹ค๋ก€ ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ ์ค‘ ๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด ์ด ์ž„์˜์ ์ธ ๋””์ž์ธ ์„ ํƒ ๋•Œ๋ฌธ์— ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ œ๊ฑฐ ์ค‘์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ๋” ํ•ฉ๋ฆฌ์ ์ด์ง€ ์•Š์Šต๋‹ˆ๊นŒ? next.config.js ํ•˜๊ณ  ๊ธฐ๋ณธ๊ฐ’์ด ['.js'] ์ธ ์˜ต์…˜์ด ์žˆ๊ฑฐ๋‚˜ Jest์˜ ๊ฒฝ์šฐ .test.js ๋˜๋Š” .spec.js ์™€ ๊ฐ™์€ ๊ฒƒ์„ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค.

ํŽธ์ง‘: TypeScript์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ์„œ๋ฒ„๋„ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜๋ฏ€๋กœ TypeScript ์˜ˆ์ œ์—์„œ tsc ์ ‘๊ทผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ .tsx ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

.jsx ์•„์ง ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๊นŒ? ๋˜ํ•œ React ๊ตฌ์„ฑ ์š”์†Œ์— .jsx ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ‘œ์ค€์ด๊ธฐ ๋•Œ๋ฌธ์— ํšŒ์‚ฌ์—์„œ next.js ์‚ฌ์šฉ์„ ์ฐจ๋‹จํ•˜๋Š” ๋ฌธ์ œ์— ์ง๋ฉดํ•ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ์‚ฌ์†Œํ•ด ๋ณด์ด์ง€๋งŒ ์šฐ๋ฆฌ ํŒ€์ด Next๋ฅผ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์„ ์ •๋‹นํ™”ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋งŒ๋“ ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•ต์‹ฌ ํŒ€์˜ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ด ๊ฒ‰๋ณด๊ธฐ์— ์ค‘์š”ํ•˜์ง€ ์•Š์€ ๋””์ž์ธ ๊ฒฐ์ •์— ๋Œ€ํ•ด ์กฐ๊ธˆ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

.jsx ํ™•์žฅ ์ง€์›์„ ์œ„ํ•ด +1

.jsx ์ง€์›์„ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ... SSR์€ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€๋งŒ ์ฝ”๋“œ์—์„œ ๋ฌด์–ธ๊ฐ€๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ํ•ซ ๋ฆฌ๋กœ๋“œํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. F5์™€ ๋ถ, ์˜ค๋ฅ˜.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

const originalJS = "/\\.js(\\?[^?]*)?$/";

config.resolve.extensions = [".js", ".jsx", ".json"];
config.module.rules.forEach((rule) => {
    if (String(rule.test) === originalJS) {
        rule.test = /\.jsx?(\?[^?]*)?$/;
    }
});

๋งŽ์€ ์‚ฌ๋žŒ๋“ค๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋‚˜๋Š” ์ด๊ฒƒ์ด ์™œ ์ผ์–ด๋‚  ์ˆ˜ ์—†๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋งŽ์€ ์‚ฌ๋žŒ๋“ค์ด jsx ์‚ฌ์šฉ์ด๋ผ๋Š” ๋ฆฐํ„ฐ ๊ตฌ์„ฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํŽธ์ง‘์ž๋Š” ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜ js์™€ jsx๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ  ... ์ง„์ง€ํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ ‡๊ฒŒ ํฐ ๋ฌธ์ œ์ž…๋‹ˆ๊นŒ? ์ฝ”๋“œ๋ฅผ ์ถฉ๋ถ„ํžˆ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ํ˜ผ์ž ํ•˜๊ฒ ์ง€๋งŒ...

ํ”Œ๋ฆฌ์ฆˆ

.jsx ๊ฐ€ "์ฆ‰์‹œ" ์ž‘๋™ํ•  ๊ฒƒ์œผ๋กœ ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์•„์ด๋””์–ด์— ๋Œ€ํ•ด ๋” ๋งŽ์€ ์ง€์›์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ํŒŒ์•…ํ•˜๊ณ (์ด ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•˜๋ฉด) ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์‚ฌ์†Œํ•˜์ง€๋งŒ ์ œ ๊ฒฝํ—˜์ƒ .jsx ํ™•์žฅ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ _๋„๋ฆฌ ์ฑ„ํƒ๋œ ๊ด€๋ก€_(์—ฌ๊ธฐ์„œ ์˜๋„์ ์œผ๋กœ "๊ถŒ์žฅ" ํ‘œํ˜„์„ ํ”ผํ•จ)์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ React ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” ํŒŒ์ผ์˜ ๊ฒฝ์šฐ.

ํ™•์žฅ ๊ธฐ๋Šฅ์„ ๊ต์ฒดํ•˜๊ณ  ๊ณ„์† ์ง„ํ–‰ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์™œ ์ด์— ๋Œ€ํ•œ ์ €ํ•ญ์ด ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ํ•ฉ๋‹นํ•œ ์š”์ฒญ์ด๋ผ๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์ค‘์š”ํ•œ ๊ฒƒ์€ ๋งŽ์€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์ด๋ฉฐ (๊ฑฐ์˜) ์ง„์ž… ์žฅ๋ฒฝ์ด ๋†’์•„์ง‘๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์„ ํ™•์žฅ์œผ๋กœ .jsx ์˜ ์žฅ์ ์— ๋Œ€ํ•œ ๋…ผ์Ÿ์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์ง€๋Š” ์•Š์ง€๋งŒ .js ์—์„œ ์œ ํšจํ•œ JavaScript๋งŒ ์›ํ•œ๋‹ค๋Š” ๊ฒƒ์ด ์™„์ „ํžˆ ๋ถˆํ•ฉ๋ฆฌํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋ผ๊ณ  ๋งํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

Btw, ์ด์ œ ๋ง‰ ์‹œ์ž‘ํ–ˆ์ง€๋งŒ ์ง€๊ธˆ๊นŒ์ง€๋Š” ์‚ฌ๋ž‘ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ๋ฉ‹์ง„ ์ž‘์—…์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

์•„๋งˆ๋„ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. .md ํ™•์žฅ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„( .md.js )์—์„œ ์ž‘๋™ํ•˜๋„๋ก ํ•˜๋ ค๋ฉด ๋‹ค์Œ ํŠธ๋ฆญ์„ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

next.config.js

// ...
          {
            test: /\.md\.js$/,
            loader: 'raw-loader',
          },
// ...

๋‚˜๋Š” airbnb์™€ ํ•จ๊ป˜ eslint๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ฒฝ๊ณ ๋ฅผ ์นจ๋ฌต์‹œํ‚ค๋Š” ๋˜ ๋‹ค๋ฅธ ๊ทœ์น™์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

{
    "extends": "airbnb",
    "rules": {
        "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
    }
}

.jsx ํŒŒ์ผ์ด ์žˆ๋Š” ์‹ค์ œ ์˜ˆ์ œ๊ฐ€ ์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

  • pages ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด๋ถ€,
  • ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง ์ž‘์—…
  • ๋‹ค๋ฅธ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ๋ชจ๋“ˆ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ

?

์ด๊ฒƒ์€ /examples ๋””๋ ‰ํ† ๋ฆฌ์— ํฐ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

+1 jsx ์ง€์› ์ถ”๊ฐ€.

@rossipedia ๊ฐ€ ์ œ์•ˆํ•œ ๊ฒƒ๊ณผ ์œ ์‚ฌํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋ฌธ์ œ๋ฅผ

์•„์ง ์—†์œผ๋ฉด ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— next.config.js ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ ๋‹ค์Œ config.resolve.extensions ๋ฐฐ์—ด์— 'jsx'๋ฅผ ํ‘ธ์‹œํ•˜๋ฉด ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

module.exports = {
  webpack: function (config, { isServer }) {
    config.resolve.extensions.push('.jsx');
    return config
  }
}

ํŽธ์ง‘ํ•˜๋‹ค
์ด ์ˆ˜์ •์€ ์„ฑ๋Šฅ์— ๋‚˜์œ ์˜ํ–ฅ์„ ๋ฏธ์น  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์กฐ์‚ฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ v5๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๋ฌด์—‡์ด๋“  ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. .jsx ํ™•์žฅ์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค. ์„ฑ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ๊ฒƒ์ด ๋ณด์ด๋ฉด next@canary๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•ด ๋ณด์‹ญ์‹œ์˜ค

๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ๋ˆˆ์น˜ ์ฑ˜๋‹ค, ๊ต‰์žฅํ•˜๋‹ค!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰