[fix] babel-plugin option to rewrite to commonjs paths

Allow the babel plugin to be configured to rewrite paths to either ES
modules (default) or CommonJS.

Ref #961
This commit is contained in:
Nicolas Gallagher
2018-05-24 19:12:03 -07:00
parent e0f010da47
commit 026a92fd53
5 changed files with 84 additions and 14 deletions

View File

@@ -17,10 +17,18 @@ yarn add --dev babel-plugin-react-native-web
```
{
"plugins": ["react-native-web"]
"plugins": [
["react-native-web", { commonjs: true }]
]
}
```
You should configure the plugin to match the module format used by your
bundler. Most modern bundlers will use a package's ES modules by default (i.e.,
if `package.json` has a `module` field). But if you need the plugin to rewrite
import paths to point to CommonJS modules, you must set the `commonjs` option
to `true`.
## Example
NOTE: `react-native-web` internal paths are _not stable_ and you must not rely

View File

@@ -48,6 +48,24 @@ import * as ReactNativeModules from 'react-native-web/dist/index';
"
`;
exports[`Rewrite react-native to react-native-web import from "native-native": import from "native-native" 2`] = `
"
import ReactNative from 'react-native';
import { View } from 'react-native';
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
import * as ReactNativeModules from 'react-native';
↓ ↓ ↓ ↓ ↓ ↓
import ReactNative from 'react-native-web/dist/cjs/index';
import View from 'react-native-web/dist/cjs/exports/View';
import { Invalid } from 'react-native-web/dist/cjs/index';
import MyView from 'react-native-web/dist/cjs/exports/View';
import ViewPropTypes from 'react-native-web/dist/cjs/exports/ViewPropTypes';
import * as ReactNativeModules from 'react-native-web/dist/cjs/index';
"
`;
exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = `
"
import { createElement } from 'react-native-web';
@@ -70,7 +88,7 @@ exports[`Rewrite react-native to react-native-web require "react-native": requir
"
const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
↓ ↓ ↓ ↓ ↓ ↓
@@ -84,6 +102,24 @@ const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity
"
`;
exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 2`] = `
"
const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');
↓ ↓ ↓ ↓ ↓ ↓
const ReactNative = require('react-native-web/dist/cjs/index').default;
const View = require('react-native-web/dist/cjs/exports/View').default;
const StyleSheet = require('react-native-web/dist/cjs/exports/StyleSheet').default;
const TouchableOpacity = require('react-native-web/dist/cjs/exports/TouchableOpacity').default;
"
`;
exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = `
"
const ReactNative = require('react-native-web');

View File

@@ -11,6 +11,15 @@ import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
import * as ReactNativeModules from 'react-native';`,
snapshot: true
},
{
title: 'import from "native-native"',
code: `import ReactNative from 'react-native';
import { View } from 'react-native';
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
import * as ReactNativeModules from 'react-native';`,
snapshot: true,
pluginOptions: { commonjs: true }
},
{
title: 'import from "react-native-web"',
code: `import { createElement } from 'react-native-web';
@@ -34,9 +43,17 @@ export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web
title: 'require "react-native"',
code: `const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');`,
const { StyleSheet, TouchableOpacity } = require('react-native');`,
snapshot: true
},
{
title: 'require "react-native"',
code: `const ReactNative = require('react-native');
const { View } = require('react-native');
const { StyleSheet, TouchableOpacity } = require('react-native');`,
snapshot: true,
pluginOptions: { commonjs: true }
},
{
title: 'require "react-native-web"',
code: `const ReactNative = require('react-native-web');

View File

@@ -1,7 +1,15 @@
const moduleMap = require('./moduleMap');
const getDistLocation = importName =>
importName && moduleMap[importName] ? `react-native-web/dist/exports/${importName}` : undefined;
const isCommonJS = opts => opts.commonjs === true;
const getDistLocation = (importName, opts) => {
const format = isCommonJS(opts) ? 'cjs/' : '';
if (importName === 'index') {
return `react-native-web/dist/${format}index`;
} else if (importName && moduleMap[importName]) {
return `react-native-web/dist/${format}exports/${importName}`;
}
};
const isReactNativeRequire = (t, node) => {
const { declarations } = node;
@@ -35,7 +43,7 @@ module.exports = function({ types: t }) {
.map(specifier => {
if (t.isImportSpecifier(specifier)) {
const importName = specifier.imported.name;
const distLocation = getDistLocation(importName);
const distLocation = getDistLocation(importName, state.opts);
if (distLocation) {
return t.importDeclaration(
@@ -46,7 +54,7 @@ module.exports = function({ types: t }) {
}
return t.importDeclaration(
[specifier],
t.stringLiteral('react-native-web/dist/index')
t.stringLiteral(getDistLocation('index', state.opts))
);
})
.filter(Boolean);
@@ -62,7 +70,7 @@ module.exports = function({ types: t }) {
if (t.isExportSpecifier(specifier)) {
const exportName = specifier.exported.name;
const localName = specifier.local.name;
const distLocation = getDistLocation(localName);
const distLocation = getDistLocation(localName, state.opts);
if (distLocation) {
return t.exportNamedDeclaration(
@@ -75,7 +83,7 @@ module.exports = function({ types: t }) {
return t.exportNamedDeclaration(
null,
[specifier],
t.stringLiteral('react-native-web/dist/index')
t.stringLiteral(getDistLocation('index', state.opts))
);
})
.filter(Boolean);
@@ -89,7 +97,7 @@ module.exports = function({ types: t }) {
if (t.isObjectPattern(id)) {
const imports = id.properties
.map(identifier => {
const distLocation = getDistLocation(identifier.key.name);
const distLocation = getDistLocation(identifier.key.name, state.opts);
if (distLocation) {
return t.variableDeclaration(path.node.kind, [
t.variableDeclarator(
@@ -112,7 +120,7 @@ module.exports = function({ types: t }) {
t.identifier(name),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral('react-native-web/dist/index')
t.stringLiteral(getDistLocation('index', state.opts))
]),
t.identifier('default')
)

View File

@@ -216,14 +216,15 @@ Install webpack-related dependencies, for example:
yarn add --dev babel-loader url-loader webpack webpack-cli webpack-dev-server
```
React Native's Babel preset rewrites ES modules to CommonJS modules, preventing bundlers from automatically performing "tree-shaking" to remove
unused modules from your web app build. To help with this, you can install the following Babel plugin:
React Native's Babel preset rewrites ES modules to CommonJS modules, preventing
bundlers from automatically performing "tree-shaking" to remove unused modules
from your web app build. To help with this, you can install the following Babel
plugin:
```
yarn install --dev babel-plugin-react-native-web
```
Create a `web/webpack.config.js` file:
```js