为什么我的 webpack 包在主机上成功构建但不在 docker 容器中?
Why is my webpack bundle successfully built on host machine but is not in docker container?
我的项目有一个这样的 monorepo 结构:
babel.config.js
a-something
b-something
我的项目根目录中有 babel 配置文件,包 a-something
和 b-something
。
内部包 a-something
我有以下 webpack 配置:
const path = require('path')
module.exports = {
target: 'node',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
},
include: [
path.resolve(__dirname, 'src'),
/node_modules\/a-/,
/node_modules\/b-/
]
}
]
}
}
包内 a-something
我有以下 package.json:
{
"name": "a-something",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"prod:build": "webpack --config webpack.config.js",
"prod:start": "node build/bundle.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"graphql": "^14.5.8",
"graphql-request": "^1.8.2",
"graphql-tag": "^2.10.1",
"b-something": "^1.0.0",
"node-fetch": "^2.6.0",
"sitemap": "^5.0.0"
},
"devDependencies": {
"webpack": "3.5.6",
"@babel/polyfill": "7.7.0"
}
}
我的根 package.json 具有以下依赖项:
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"babel-loader": "8.0.6"
最后我的 Dockerfile 包 a-something
是:
FROM node:10.15.1
COPY ./package.json /src/package.json
ENV PORT 3000
ENV NODE_ENV production
WORKDIR /src
RUN npm install
COPY ./lerna.json /src/lerna.json
COPY ./packages/a-something/package.json /src/packages/a-something/package.json
COPY ./packages/b-something/package.json /src/packages/b-something/package.json
RUN npm run clean
COPY . /src
WORKDIR /src/packages/a-something
RUN npm run prod:build
RUN echo "FINISHED BUILDING!"
EXPOSE ${PORT}
CMD ["npm" , "run", "prod:start"]
当我 运行 npm run prod: build
和 npm run prod: start
成功构建包时,但是当我构建 docker (上下文是根文件夹)时我得到以下 npm 错误:
ERROR in Entry module not found: Error: Can't resolve 'babel-loader' in '/src/packages/a-something'
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! a-something@1.0.0 prod:build: `webpack --config webpack.config.js`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the a-something@1.0.0 prod:build script.
我的主机 OS 是 macOS Mojave。也许 Lerna 生成的符号链接在 Debian 上的处理方式不同(由节点 image 使用)?
更新: 通过将所有与 babel 相关的 npm 包从 devDependencies
移动到根 package.json 的 dependencies
部分解决了这个问题。有谁知道为什么这会解决问题?
正如我在问题的更新部分提到的,解决方案是将所有与 babel 相关的包移动到根 package.json.
的 devDependencies
部分
但这为什么有帮助?
问题是我在 Dockerfile 中将 NODE_ENV
设置为生产环境。 npm will not install dev dependencies if NODE_ENV
is set to production. On the host machine I didn't have such variable. In addition another issue would've been @babel/polyfill
, according to babel docs:
Because this is a polyfill (which will run before your source code),
we need it to be a dependency, not a devDependency
根据 docs @babel/polyfill
也已弃用,因此更好的解决方案是:
- 将
"babel-loader": "8.0.6"
添加到根 package.json
- 在
a-something
package.json中有以下devDependencies
:
"devDependencies": {
"webpack": "3.5.6",
"core-js": "^3.4.7",
"regenerator-runtime": "^0.13.3"
}
- 将这两行放在最顶部的条目 Javascript 文件中:
import 'core-js/stable'
import 'regenerator-runtime/runtime'
- 最后使用这个 webpack 配置:
const path = require('path')
module.exports = {
target: 'node',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
rootMode: 'upward',
presets: [
['@babel/preset-env', {
corejs: 3,
useBuiltIns: 'usage'
}]
]
}
},
include: [
path.resolve(__dirname, 'src'),
/node_modules\/a-/,
/node_modules\/b-/
]
}
]
}
}
我的项目有一个这样的 monorepo 结构:
babel.config.js
a-something
b-something
我的项目根目录中有 babel 配置文件,包 a-something
和 b-something
。
内部包 a-something
我有以下 webpack 配置:
const path = require('path')
module.exports = {
target: 'node',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
},
include: [
path.resolve(__dirname, 'src'),
/node_modules\/a-/,
/node_modules\/b-/
]
}
]
}
}
包内 a-something
我有以下 package.json:
{
"name": "a-something",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"prod:build": "webpack --config webpack.config.js",
"prod:start": "node build/bundle.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.2",
"graphql": "^14.5.8",
"graphql-request": "^1.8.2",
"graphql-tag": "^2.10.1",
"b-something": "^1.0.0",
"node-fetch": "^2.6.0",
"sitemap": "^5.0.0"
},
"devDependencies": {
"webpack": "3.5.6",
"@babel/polyfill": "7.7.0"
}
}
我的根 package.json 具有以下依赖项:
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"babel-loader": "8.0.6"
最后我的 Dockerfile 包 a-something
是:
FROM node:10.15.1
COPY ./package.json /src/package.json
ENV PORT 3000
ENV NODE_ENV production
WORKDIR /src
RUN npm install
COPY ./lerna.json /src/lerna.json
COPY ./packages/a-something/package.json /src/packages/a-something/package.json
COPY ./packages/b-something/package.json /src/packages/b-something/package.json
RUN npm run clean
COPY . /src
WORKDIR /src/packages/a-something
RUN npm run prod:build
RUN echo "FINISHED BUILDING!"
EXPOSE ${PORT}
CMD ["npm" , "run", "prod:start"]
当我 运行 npm run prod: build
和 npm run prod: start
成功构建包时,但是当我构建 docker (上下文是根文件夹)时我得到以下 npm 错误:
ERROR in Entry module not found: Error: Can't resolve 'babel-loader' in '/src/packages/a-something'
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! a-something@1.0.0 prod:build: `webpack --config webpack.config.js`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the a-something@1.0.0 prod:build script.
我的主机 OS 是 macOS Mojave。也许 Lerna 生成的符号链接在 Debian 上的处理方式不同(由节点 image 使用)?
更新: 通过将所有与 babel 相关的 npm 包从 devDependencies
移动到根 package.json 的 dependencies
部分解决了这个问题。有谁知道为什么这会解决问题?
正如我在问题的更新部分提到的,解决方案是将所有与 babel 相关的包移动到根 package.json.
的devDependencies
部分
但这为什么有帮助?
问题是我在 Dockerfile 中将 NODE_ENV
设置为生产环境。 npm will not install dev dependencies if NODE_ENV
is set to production. On the host machine I didn't have such variable. In addition another issue would've been @babel/polyfill
, according to babel docs:
Because this is a polyfill (which will run before your source code), we need it to be a dependency, not a devDependency
根据 docs @babel/polyfill
也已弃用,因此更好的解决方案是:
- 将
"babel-loader": "8.0.6"
添加到根 package.json - 在
a-something
package.json中有以下devDependencies
:
"devDependencies": {
"webpack": "3.5.6",
"core-js": "^3.4.7",
"regenerator-runtime": "^0.13.3"
}
- 将这两行放在最顶部的条目 Javascript 文件中:
import 'core-js/stable'
import 'regenerator-runtime/runtime'
- 最后使用这个 webpack 配置:
const path = require('path')
module.exports = {
target: 'node',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
rootMode: 'upward',
presets: [
['@babel/preset-env', {
corejs: 3,
useBuiltIns: 'usage'
}]
]
}
},
include: [
path.resolve(__dirname, 'src'),
/node_modules\/a-/,
/node_modules\/b-/
]
}
]
}
}