rollup|rollup react 常见问题解决大法(转载)

(转载) Marvin's Blog【程式人生】 原文链接:https://marvinsblog.net/
Ability will never catch up with the demand for it

  • Home
  • Tags
  • Categories
  • Topics
23Dec 2018
用Rollup打包Typescript和React 前端项目最麻烦的问题是如何解决代码间的依赖,以及如果打包代码。目前比较主流的代码打包工具有webpack和rollup。我比较喜欢后者,因为配置比较简单,而且一上来就支持es6.
我的需求是要把react和typescript打包到一起。react提供了一个工具Create React App,可以帮助你快速搭建一个react app项目。但是Create React App默认支持的是webpack,而不是我希望的rollup。所以本文研究如何用rollup来打包react和typescript。
实验过程 创建项目
首先创建一个项目demo,并添加react相关的依赖(react,react-dom):
mkdir demo cd demo yarn add react react-dom

上面的命令会在当前目录生成node_modules package.json yarn.lock
添加typescript
然后添加typescript到dev依赖中
yarn add --dev typescript

创建里面tsconfig.json文件,用来配置typescript,内容如下:
{ "compilerOptions": { "target": "es6", "jsx": "react", "sourceMap": true, "module": "commonjs" }, "exclude": [ "node_modules" ] }

上面的配置让typescript能够转译tsx文件(也就是ts版的jsx文件),并生成es6代码。
demo.tsx
现在来编写一个小例子demo.tsx,内容如下:
import * as React from "react"; import * as ReactDOM from "react-dom"; ReactDOM.render(Hello, Welcome to the first page , document.getElementById("root") );

可以使用./node_modules/.bin/tsc -b命令来编译上面的例子,会生成demo.js,其内容如下:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const React = require("react"); const ReactDOM = require("react-dom"); ReactDOM.render(React.createElement("div", null, React.createElement("h1", null, "Hello, Welcome to the first page")), document.getElementById("root")); //# sourceMappingURL=demo.js.map

添加rollup
下面的命令在dev依赖中添加rollup以及rollup的两个plugin:rollup-plugin-commonjs和rollup-plugin-node-resolve
yarn add --dev rollup rollup rollup-plugin-commonjs rollup-plugin-node-resolve

我们还需要添加rollup的typescript相关的plugin
yarn add --dev rollup-plugin-typescript tslib

添加tslib,是因为它是rollup-plugin-typescript的peer依赖
创建rollup的配置文件rollup.config.js,添加以下内容
import typescript from 'rollup-plugin-typescript' import commonjs from 'rollup-plugin-commonjs' import resolve from 'rollup-plugin-node-resolve'export default { input: './demo.tsx', output: { file: 'dist/index.js', format: 'iife', exports: 'named', sourcemap: true }, plugins: [ typescript(), resolve(), commonjs() ] }

Missing exports错误
使用./node_modules/.bin/rollup -c来打包当前项目,不料却出现若干问题:
./demo.tsx → dist/index.js... (!) Missing exports https://rollupjs.org/guide/en#error-name-is-not-exported-by-module- demo.tsx render is not exported by node_modules/react-dom/index.js ... createElement is not exported by node_modules/react/index.js ... createElement is not exported by node_modules/react/index.js ...

解决办法一 一个解决办法是使用rollup-plugin-commonjs的custom-named-exports功能,这需要修改rollup.config.js的plugin配置中的commonjs部分:
commonjs({ namedExports: { 'node_modules/react/index.js': ['createElement'], 'node_modules/react-dom/index.js': ['render'] } })

做完上述的配置后执行./node_modules/.bin/rollup -c,错误消除。
这个解题思路和StackOverflow的这个帖子一致
解决办法二 另一个解决办法,在Making of a component library for React一文中提到的,是在rollup.confg.js中把react和react-dom作为外部依赖。
修改rollup.config.js:
export default { input: './demo.tsx', output: { file: 'dist/index.js', format: 'iife', exports: 'named', sourcemap: true, // 添加globals globals: { react: 'React', 'react-dom': 'ReactDOM' } }, // 添加externs external: ['react', 'react-dom'], plugins: [ typescript(), resolve(), // 取消之前对commonjs的配置 commonjs() ] }

这样做的好处是./node_modules/.bin/rollup -c执行非常快,因为不需要打包react和react-dom;坏处是需要自己在html中添加react和react-dom,例如:

上面的例子参考了react-rectangle-popup-menu
解决办法三 解决办法三和解决办法二相似,但是使用到了peer依赖。这个解决办法来自于create-react-library。它可以用来创建基于rollup和typescript的react库。
create-react-library把react和react-dom在package.json中列为了peerDependencies(在yarn add的时候指定–peer即可)。然后使用rollup-plugin-peer-deps-external插件,这个插件可以把让rollup把所有的peerDependencies当成external依赖处理。最后的效果跟解决办法二类似
解决办法四 如果我们在demo.tsx里面把下面的代码:
import * as React from "react"; import * as ReactDOM from "react-dom";

改成
import React from "react"; import ReactDOM from "react-dom";

那么错误有可能变成:
[!] Error: 'default' is not exported by node_modules/react-dom/index.js

【rollup|rollup react 常见问题解决大法(转载)】有一个小戏法能够帮助解决这个问题,那就是在rollup.config.js中使用rollup-plugin-replace插件:
import replace from 'rollup-plugin-replace' ... export default { ... plugins: [ replace({ 'process.env.NODE_ENV': JSON.stringify('devolpment') }), // 或者production ...

在nodejs中把环境变量process.env.NODE_ENV改成development或者production,这个错误就会消失,实在不知道是为什么呢? buble-react-rollup-starter也是这样??做的。
其他参考 typescript和reactjs相关
  • [How & why: A guide to using Typescript with React](How & why: A guide to using Typescript with Reacthttps://blog.logrocket.com/how-why-a-guide-to-using-typescript-with-react-fffb76c61614)
  • ES6: import * as React vs import React
  • import fails with ‘no default export’ #8
  • Migrating from create-react-app-typescript to Create React App
  • What exactly is the ‘react-scripts start’ command?
rollup相关
  • Rollup - react.js does not export Component #643
  • NamedModules: cloneElement is not exported by react #345
  • Rollup Error: ‘isValidElementType’ is not exported by node_modules/react-is/index.js
  • Is “named exports” feature or bug? #211
nodejs依赖
  • https://yarnpkg.com/lang/en/docs/dependency-types/
  • http://npm.github.io/using-pkgs-docs/package-json/types/peerdependencies.html
  • https://nodejs.org/en/blog/npm/peer-dependencies/
  • https://stackoverflow.com/questions/26737819/why-use-peer-dependencies-in-npm-for-plugins
JS模块
  • how to use node.js module system on the clientside
  • Learn the basics of the JavaScript module system and build your own library
打包器
  • Webpack and Rollup: the same but different
  • Rollup v. Webpack v. Parcel
其他starter
  • Creating a React App… From Scratch.
  • https://github.com/Microsoft/TypeScript-React-Starter
  • Guide to building a React components library with Rollup and styled-jsx.
  • How I set-up a React component library with Rollup
Categories
frontend programming
Tags
reactjs rollupjs typescript
comments powered by Disqus

    推荐阅读