我编写了一个实用程序库,当我的用户tree-shaking
他们的应用程序时,我想publishes
他们。
在Webpack v4中,您需要使模块ES6
支持tree-shaking
,但是我也想将development build
和production build
拆分为不同的文件。 / p>
我想要的就像是React的NPM模块:
// index.js
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react.production.min.js');
} else {
module.exports = require('./cjs/react.development.js');
}
这给我带来了疑问。
如果我将实用程序模块全部设为commonjs
,我将永远无法得到tree-shaking
,我的应用程序将会变得如此庞大。
如果我的实用程序模块全部为ES6 static export
,则必须在development message
中包含production code
。
发布两个模块(例如:my-utility
和my-utility-es
)将无济于事,因为在开发中,我的代码如下:
import { someFunc } from 'my-utility';
但是在生产代码中,我将不得不将其更改为:
import { someFunc } from 'my-utility-es';
我该如何解决这个问题?
更清楚地说,我的development build
和production build
包含不同的源代码(例如:生产版本删除了所有错误消息)。
所以指定webpack模式对我来说并不令人满意。
答案 0 :(得分:2)
我自己找到了答案,我认为最好的方法是通过babel macros
:
import { something } from 'myLibrary/macro';
// In webpack development:
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
// import { something } from 'myLibrary/development';
// In webpack production:
// ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
// import { something } from 'myLibrary/production';
我的宏实现:
import { createMacro } from 'babel-plugin-macros';
function macro({ references, state, babel }) {
state.file.path.node.body.forEach(node => {
if (node.type === 'ImportDeclaration') {
if (node.source.value.includes('myLibrary/macro')) {
if (process.env.NODE_ENV === 'production') {
node.source.value = 'myLibrary/module/production';
} else {
node.source.value = 'myLibrary/module/development';
}
}
}
});
return { keepImports: true };
}
export default createMacro(macro);
答案 1 :(得分:1)
这是我找到的最好的解决方案,不需要用户使用Babel宏...
crazy-components
ComponentA
和ComponentB
的React组件// src/index.js
import React from 'react';
export function ComponentA(props) {
if (process.env.NODE_ENV !== 'production') {
console.log(`Rendering ComponentA with props ${props}`);
}
return <div>ComponentA message: {props.msg}</div>;
}
export function ComponentB(props) {
if (process.env.NODE_ENV !== 'production') {
console.log(`Rendering ComponentB with props ${props}`);
}
return <div>ComponentB message: {props.msg}</div>;
}
是可摇树的,因此如果用户使用import { ComponentA } from 'crazy-components'
,则ComponentB
的代码将不会出现在其捆绑包中。
从生产包中剥离了日志记录代码。
CJS构建输出到/dist/cjs
,ESM构建输出到/dist/esm
。文件分别称为crazy-components.prod.min.js
和crazy-components.dev.js
。
仅开发版本包含日志记录代码(没有解释如何完成所有这些操作,如果您正在阅读此书,您可能已经知道了)。
// index.js
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/cjs/crazy-components.min.js');
} else {
module.exports = require('./dist/cjs/crazy-components.js');
}
// es/index.js
import {
ComponentA as ComponentA_prod,
ComponentB as ComponentA_prod
} from '../dist/esm/crazy-components.prod.min.js';
import {
ComponentA as ComponentA_dev,
ComponentB as ComponentA_dev
} from '../dist/esm/crazy-components.dev.js';
export const ComponentA = process.env.NODE_ENV === 'production' ? ComponentA_prod : ComponentA_dev;
export const ComponentB = process.env.NODE_ENV === 'production' ? ComponentB_prod : ComponentB_dev;
package.json
中的两个入口点:// package.json
{
"name": "crazy-components",
"version": "1.0.0",
"main": "index.js",
"module": "es/index.js",
"sideEffects": false
}
节点12(带有标志)和节点13+ support ES modules natively。
添加到package.json
:
"exports": {
".": {
"import": "./es/index.js",
"require": "./index.js"
},
"./es": "./es/index.js"
},
在package.json
文件夹中添加额外的es
文件,以将该文件夹的内容标记为对NodeJS的ESM:
// es/package.json
{
"type": "module"
}
使用rollup-plugin-copy来获取汇总,并将该文件也复制到dist/esm
中:
// rollup.config.js
import copy from 'rollup-plugin-copy';
/* ... other imports ... */
export default {
input: 'src/index.js',
/* ... other config ... */
plugins: [
/* ... other plugins ... */
copy({targets: [{src: 'es/package.json', dest: 'dist/esm'}]})
]
};
es/index.js
是手工创建的,因此如果以后添加ComponentC
,它也需要添加到es/index.js
中。如果有一个Rollup插件可以自动创建es/index.js
,那是理想的选择,但是我还没有找到。
此外,您的里程可能会有所不同。我今天才刚刚尝试过。在create-react-app应用程序中导入库后,它似乎可以按预期工作,但是我尚未使用手动编码的Webpack配置对其进行过测试。
这种方法应该可以推广到任何库,不仅是React组件,而且我还没有尝试过。
非常欢迎任何改进建议!
答案 2 :(得分:0)
解决此问题所需要做的就是使用mode
。参见Specify the Mode。
自webpack v4起,指定模式会自动为您配置DefinePlugin:
webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});
他们提到了React的名字:
如果您使用的是类似react之类的库,那么添加此插件后,捆绑包的大小实际上应该会明显下降。