node 패키지 브라우저에서 사용하기 (with Webpack 4)
fs
, path
와 같은 NodeJS Built-In 모듈을 사용하는 패키지를 브라우저에서 동작하도록 땜질식(?)으로 번들링해본 후기입니다.간단한 결론만 원하신다면 Summary 를 참고하세요.
이유
문제점
fs
, path
와 같은 built-in 모듈을 사용하는 패키지를 웹팩을 이용해 번들해야 했는데 번들시 해당 모듈을 찾지 못해 아래와 같은 에러가 발생하게 됩니다.ERROR in ./node_modules/@eslint/eslintrc/lib/config-array-factory.js
Module not found: Error: Can't resolve 'fs' in '...project/node_modules/@eslint/eslintrc/lib'
- NodeJS Built-In 모듈을 사용하지만, 런타임에는 필요 없는 모듈
- NodeJS Built-In 모듈을 사용하고, 런타임에도 필요한 모듈
해결 1. 런타임에 필요 없는 모듈
null-loader
를 설치합니다.$ npm install null-loader --save-dev
rules
에 아래와 같이 null-loader
를 추가해 줍니다. test
에는 비어있는 모듈로 교체할 모듈을 명시해 줍니다.webpack.config.js module.exports = { rules: [ //... { test: [ /\/eslint\/.*\/cli-engine/, // ... ], use: "null-loader" } ] }
null-loader
에 test
에 설정한 모듈은 비어있는 모듈이 됩니다. 아무런 기능이 없는 모듈이 번들되게 되지만 실제로 런타임에는 사용되지 않기 때문에 동작에 아무런 문제가 되지 않습니다.해결 2: 런타임에도 필요한 모듈
fs
를 사용하고 있습니다. 때문에 typescript-eslint 를 번들시 globby 에서 fs
를 찾지 못한다는 에러가 발생하게 됩니다.- @typescript-eslint/parser
import { sync as globSync } from 'globby'; //... function prepareAndTransformProjects() { //... globSync([...globbedProjects, ...ignoreListInput], { cwd: extra.tsconfigRootDir, }); }
/src/modules/globby.js // src/modules/globby.js module.exports = { sync() { return ["./tsconfig.json"]; }, };
plugins
에 NormalModuleReplacementPlugin로 해당 모듈을 대체할 커스텀 모듈로 대체합니다.webpack.config.js const webpack = require('webpack'); module.exports = { //... plugins: [ new webpack.NormalModuleReplacementPlugin( /globby/, // 교체 대상 모듈 "src/modules/globby.js" // 대신 사용할 모듈 ), ] }
src/modules/globby.js
로 대체되게 됩니다.결론
null-loader
나 NormalModuleReplacementPlugin
으로 땜질(?)하듯이 작업해야 했습니다.typescript-eslint 에서 구조 리팩터링이 있다면 ... 웹팩을 다시 설정해야겠죠..?
Summary
fs
, path
와 같은 NodeJS 모듈을 사용하는 패키지를 웹팩으로 번들하는 경우, 런타임에 필요없는 모듈은 null-loader, 런타임에도 필요한 모듈은 NormalModuleReplacementPlugin 를 활용해 보세요.