I have a React component library that is used in a React app. The component library is setup using Styleguidist and webpack. I've setup webpack to use absolute paths using:
webpackConfig: {
resolve: {
modules: [path.resolve(__dirname, 'src/'), 'node_modules'],
}
}
This works within the context of the component library. When I build the component library, the package looks like this:
/core
/components
/Table
/Row
When I import the components into my app, I get an error:
Module not found: Can't resolve components/Row in /Users/myusername/Sites/mysite/node_modules/#mypackage/core/components/Table
I understand why the paths don't match in the context of node_modules, but I would've expected Webpack to transform those import paths during the build process. Is there something I'm missing? Or is this not possible?
While Styleguidist uses webpack, it turns out the build script we were using does not, so the webpack config is irrelevant. Instead, our build script (https://www.npmjs.com/package/cod-scripts) uses babel.
We ended up having to add a separate babel.config.js file to define absolute paths for babel using the babel-plugin-module-resolver package.
npm install babel-plugin-module-resolver --saveDev
npm install #babel/preset-react --saveDev
babel.config.js
module.exports = {
plugins: [
[
'module-resolver',
{
root: ['./src'],
},
],
],
presets: ['#babel/preset-react'],
};
Related
I created a module using CRA (Create-React-App) - typescript and published the same to npm.
My goal is to add the module as a component in another CRA created typescript project. When I try to import the module it fails with below error.
Cannot find module: 'fbdemots'. Make sure this package is installed.
I do see the modules in the path "node_modules\fbdemots".
I tried the below which did not help
Creating declaration files(d.ts) both in the module and the project which uses the module
Updating the TSConfig as mentioned in below link
Below links does not help, as I cannot change the
"module": "esnext", --> to "CommonJS" since CRA (Create-React-App) does not allow me to.
"moduleResolution": "node", "esModuleInterop" : "true"
`Cannot find module` for my own TypeScript module
Wait! Why I see the fbdemots of node_modules is a project, not component, and it can't be exported at all
If you want to publish a component, you can follow these common steps, of course there are other methods you can try.
If you don't want to use rollup/webpack or feel a bit complicated, you can just export your plain component, and then publish it.
1. Create a component and export it
// index.tsx
import React from 'react'
const Test = (props: {a: string})=> <div>{props.a}</div>
export default Test
2. Using rollup or Webpack to build it to make sure it would be usable for JS modules
Install some necessary modules
yarn add --dev rollup rollup-plugin-typescript2
Then create rollup.config.js file at root, if there are other files like '.css', '.scss', then you should install and add some plugins like rollup-plugin-sass or rollup-plugin-css-only...
// rollup.config.js
import typescript from 'rollup-plugin-typescript2';
// import sass from 'rollup-plugin-sass';
export default {
input: 'index.tsx', // the path of your source file
output: [
{
dir: 'lib',
format: 'cjs',
exports: 'named',
sourcemap: false,
strict: false,
},
],
plugins: [typescript()],
// plugins: [sass({ insert: true }), typescript()],
external: ['react', 'react-dom'],
};
3. Create lib
Using the command of rollup to build it
npx rollup -c
And then prepare package.json, LICENSE, README.md... into lib dir,
finally you can publish it
npm publish ./lib --access public
The end of the last, you can add it as a component in another CRA created typescript project!
I have my create-react-app bootstrap workspace setup to support module imports using #app/ as my root module.
I achieve this by adding this to my webpack config
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
'#app': path.resolve(__dirname, '../src')
},
However this does not seem to work with my jest tests. Anytime something is imported with #app the import is not resolved.
Anyone have a good solution to this
I've built a wrapper package for drag and drop in React, and I added storybook examples.
Since in my consumer React is exposed globally, i'm not importing React explicitly.
In the storybook examples I need to supply React as part of the custom webpack config, but for some reason it can't resolve React and I get a ReferenceError: React is not defined
This is the package - https://github.com/fiverr/drag_n_drop_package
And this is the custom webpack config file:
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.ProvidePlugin({
React: 'react'
})
],
module: {
loaders: [
{
test: /\.scss$/,
loader: 'style!raw!sass'
}
]
}
};
This is really strange but your storybook webpack.config.js is mixing webpack v1/v2.
Importing webpack as
const webpack = require('#kadira/storybook/node_modules/webpack');
solves it because it uses the same webpack reference that storybook is using (v1).
I found the following code in webpack.config.js at github:
externals: {
react: 'React'
}
It looks as this question. If it needs to load the React lib from external, like CDN. The page has to be sure have a script tag for importing React lib. And make sure this script tag is in front of the bundle.js or the file which it generated by webpack, so the Object of React will exist when the following code needs to use React, such as:
<script src="./react.js"></script>
<script src="./bundle.js"></script>
TL;DR: I'm getting build files that are way too big. I want them to be small and use the React source files from a CDN.
My Gulp file contains this:
gulp.task('build', () => {
browserify({
entries: dirs.src + '/index.jsx',
extensions: ['.jsx'],
debug: false
})
.transform(babelify.configure({
presets: ["es2015", "react"]
}))
.bundle()
.pipe(source('index.js'))
.pipe(gulp.dest(dirs.dest));
});
And said index.jsx file contains:
import { Provider } from 'react-redux';
import slides from './stores/slides';
const store = slides();
ReactDOM.render(
<Provider store={store}>
<h1>Test</h1>
</Provider>,
document.getElementById('target')
);
React Redux is pretty small. And if I remove that part from the latter file the result is a mere 1 KB in size. Otherwise it'll turn into 700Kb+.
I already removed these two lines from that file:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
Because I wanted to load React and ReactDOM from a CDN. Why are my files still this incredibly large?
You're currently using the development version of React. You have to build your own production version, for that the process.env.NODE_ENV flag has to be set to production.
If you're using browserify, you need envify: https://github.com/hughsk/envify
npm install envify --save-dev
Your Gulpfile.js
var envify = require('envify/custom');
//...
.transform(babelify.configure({
presets: ["es2015", "react"]
}))
.transform(envify({
NODE_ENV: 'production'
}))
//...
More resources: http://dev.topheman.com/make-your-react-production-minified-version-with-webpack/
I'm loading Ready through script tags from a CDN. I don't want to have the entire React codebase in my own local project files.
In this case, your production Webpack config should specify React in externals config option:
{
// ...
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
// ...
}
Otherwise Webpack will bundle it.
Also verify that you don’t have a devtool option in the production config. It can bloat the code immensely if you use 'eval' or even inline sourcemaps.
I know uglify, but I don't want my code uglified
You should be using uglify for your code in production. This is the only way to have small builds.
After too many unsuccessful trials my question is: What is the proper way to setup Webpack so that:
Use react.min.js + react-dom.min.js - not the npm installed sources
Don't parse/com them again, just bundle with my own components.
"React" and "ReactDOM" variables can be used from all .jsx files.
The tutorials and guides I found didn't work - or maybe I did some errors. Usually I got error in browser developer tools about missing variable React.
My aim is just to save parsing/bundling time. Now I parse React from scratch every time I bundle my app. And it takes tens of seconds on a slowish computer. In watch mode it is faster, but I find I'm doing unnecessary work.
Any ideas with recent React versions?
Assuming you have a webpack.config.js that looks something like this:
module.exports = {
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
...
]
}
};
You just need to specify React and ReactDOM as external dependencies (from the docs):
module.exports = {
entry: "./entry.js",
output: {
path: __dirname,
filename: "bundle.js"
},
module: {
loaders: [
...
]
},
externals: {
// "node/npm module name": "name of exported library variable"
"react": "React",
"react-dom": "ReactDOM"
}
};
The key point about the externals section is that the key is the name of the module you want to reference, and the value is the name of the variable that the library exposes when used in a <script> tag.
In this example, using the following two script tags:
<script src="https://fb.me/react-0.14.6.js"></script>
<script src="https://fb.me/react-dom-0.14.6.js"></script>
results in two top-level variables being created: React and ReactDOM.
With the above externals configuration, anytime in your source code you have a require('react'), it will return the value of the global variable React instead of bundling react with your output.
However, in order to do this the page that includes your bundle must include the referenced libraries (in this case react and react-dom) before including your bundle.
Hope that helps!
*edit*
Okay I see what you're trying to do. The webpack configuration option you want is module.noParse.
This disables parsing by webpack. Therefore you cannot use dependencies. This may be useful for prepackaged libraries.
For example:
{
module: {
noParse: [
/XModule[\\\/]file\.js$/,
path.join(__dirname, "web_modules", "XModule2")
]
}
}
So you'd have your react.min.js, react-dom.min.js, and jquery.min.js files in some folder (say ./prebuilt), and then you'd require them like any other local module:
var react = require('./prebuilt/react.min');
And the entry in webpack.config.js would look something like this (untested):
{
module: {
noParse: [
/prebuilt[\\\/].*\.js$/
]
}
}
The [\\\/] mess is for matching paths on both Windows and OSX/Linux.