facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.56k stars 26.79k forks source link

Plugin System #670

Closed gaearon closed 6 years ago

gaearon commented 8 years ago

I know we said we don’t offer any configuration but...

If Create React App had a plugin system, what would it be like? Can you briefly describe build tooling plugin systems that you’ve used and liked in this thread?

If it was supported, what would you build with it?

just-boris commented 8 years ago

I like Karma test runner. It scans your package space and automatically picks up all packages named as karma-* that you have installed in the node_modules folder. No need to specify it again in any config file. Also, Karma itself is built using dependency injection pattern, which gives you an ability to easily receive and override any part of the context.

So, for create-react-app it means the following: to get something extra for your app you need to install npm install react-scripts-something. Then package will be called from the core and can do something with main configs.

arturparkhisenko commented 8 years ago

I personally like idea with a hack'y usage of base html tag plus imports of web-components, but it's works globally for all links and it's in html, anyway this is a nice idea because this lib's and components are already accessible from the internet so i don't need to download them, just use it like usual cdn's (but with options). What if in JS we could make a plugin which can do that:

superPluginImport({base: ['https://ajax.googleapis.com/ajax/libs/'], include: 'all'}); 
// use include option to select what we need, example: 'react,react-dom', 
// maybe with versions like 'react@15.3.1,react-dom@15.3.1'
// and later we can use it:
ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById('example'));

Looks like direct https://rawgit.com/ but for multiple sites. And @just-boris answer is very interesting, but why just not lazy-import everything from node_modules.

FezVrasta commented 8 years ago

plugin system... don't you encounter the risk of becoming another "grunt" thing with thousands of wrappers to use even the simplest of the libraries?

goshacmd commented 8 years ago

@just-boris Brunch does similar, instead of looking through the folders though, it just looks in the package.json for *-brunch and brunch-* and loads those. The reason for doing package and not a fs listing is to make sure cloning a repo will build the same for everyone and not turn out that Bob had this Working Locally™ but forgot to --save.

The experience of simply doing npm i -D sass-brunch and having everything Just Work is wonderful.

cesarandreu commented 8 years ago

I like webpack's plugin system. All internals are implemented as plugins. It lets you hook into any part of the system.

If you're at the point in which you need that level of flexibility, you might be better off learning how to use the underlying tools.

What are examples of scenarios which would be well served by plugins?

I think helping improve the underlying tools would go a long way towards solving many of the use-cases which come to mind. There have been docs writing up ideas about concord for a while. If it were supported, what would be the remaining gaps?

goshacmd commented 8 years ago

@cesarandreu for one, loaders. If adding a loader to create-react-app- was as simple as npm install -D react-scripts-sass and didn't require ejecting and manually changing the config, that'd be a great experience.

cesarandreu commented 8 years ago

@goshakkk Wouldn't concord solve that use-case? To some degree, at least. You'd still have some stuff to configure.

I like the idea of having a thing you can just drop in and it works. But I don't know how it can be achieved, once you start considering how it interacts with other plugins.

Will it work when someone writes a plugin for HMR? Extract stylesheets for production builds? Pass em through autoprefixer? Setup the aliases for jest? Will it work when someone adds a plugin for css modules?

I don't write this to be contrarian; I want frontend tooling to be great and approachable.

emirotin commented 8 years ago

I used to love http://mimosa.io/ (sane defaults for all the plugins, very little mandatory configuration). http://www.metalsmith.io/ is also great, but it's for programmatic usage. The biggest advantage is that the entire system is dead stupid simple, a plugin is a function, gets 3 args, can do whatever it wants to the file tree.

I like Karma test runner. It scans your package space and automatically picks up all packages named as karma-* that you have installed in the node_modules folder.

There's also a similar thing for grunt: https://www.npmjs.com/package/load-grunt-tasks

netanelgilad commented 8 years ago

Would love to be able to extend create-react-app 😍 . About what I would build if a plugin system were available: create-react-app + Typescript. For now I used create-react-app ejected files and added typescript for myself. And I can see why a plugin system would make it hard to extend create-react-app core while still supporting all the plugins out there.

I'd like to add babel plugin system as a nice example here, particularly the presets. In any plugin system, I believe presets are what would make it easy for newcomers to start hacking right away. Eventually create-react-app would come with the preset recommended by you, and others will create their own flavors.

Just as thought experiment (That I haven't explored all the way yet): What if instead of a plugin system, we create a system that exports most of it smaller parts so others can just use them and compose them in a different way? It may not be as a robust solution as a plugin system, but It would make updating the core less dependent on the created plugins.

The smallest example of what I mean: If I have function f that is implements like f(x)=g(b(x)) and let's say I want to make it pluggable then I can change it to f(x,plugin)=g(plugin(b(x))) and so others can supply the plugin for the "middle" of the function. But instead if g and b were exported and useable outside then others can just create myF(x)=g(plugin(b(x))).

gaearon commented 8 years ago

What if instead of a plugin system, we create a system that exports most of it smaller parts so others can just use them and compose them in a different way? It may not be as a robust solution as a plugin system, but It would make updating the core less dependent on the created plugins.

This is the direction I want to move towards in the future, after we land #419.

AlicanC commented 8 years ago

@gaearon I was just going to create an issue suggesting a "babel-preset-facebook".

A quote from that:

It would be a great help for people who create non-CRA apps and also for CRA-exiters since they will not end up with a (relatively) giant Babel config to manage. (Plus, they will still be receiving changes done to the preset.)

There is a need to hide configuration from users because they are complicated and confusing. Instead of hiding the ugly truth, we can prettify the truth and stop hiding it. Then people could mess with their configs without going crazy and there wouldn't be a need for a plugin system.

tmeasday commented 8 years ago

I think there are probably a few lessons to be learned from Meteor's build plugin system -- although webpack and Meteor's build tool have some pretty different starting assumptions, I think CRA's "zero-config"-ness is going to run up against a lot of the same problems we've seen in Meteor.

For instance, although it's a great developer experience just installing an npm-package and having a plugin work, it's inevitable that people are going to want to configure plugins (for instance, setting autoprefixer browser support is pretty hard to generalize!). So if there's no system for plugin configuration, plugin authors will improvise, which leads to a problematic and inconsistent developer experience.

What if instead of a plugin system, we create a system that exports most of it smaller parts so others can just use them and compose them in a different way?

On a more concrete topic, I think this is the best way to move forward if/when you decide to go 0->1 with the config. When creating saturn (an experiment in a webpack based framework, similar in aims to CRA), we tried to make it as simple as possible to consume parts of the framework or even copy them into your app, to provide a less binary escape hatch than npm run eject.

I'm still not sure if that was a good idea (I'm sure you've thought about it a bunch), but it does seem like a much more flexible alternative to "eject if you want to configure anything" :)

SeeThruHead commented 8 years ago

I particularly like kotatsus layer over webpack. Less config overall and plugins specified via cli Args optionally

insin commented 8 years ago

If adding a loader to create-react-app- was as simple as npm install -D react-scripts-sass and didn't require ejecting and manually changing the config, that'd be a great experience.

Proof of concept implementation for this: https://github.com/facebookincubator/create-react-app/commit/344893b17121ef7ba561efca3f429c1890b80352

The idea is that instead of completely opening up config to plugins (at which point someone will write a react-scripts-config plugin which reads it from a local file and now you de facto support config because everyone will use that instead of ejecting), plugins just manage dependencies and provide configuration required to implement specific features, in this case cssPreprocessors.

ccorcos commented 8 years ago

I like the idea of a "zero-configuration" build tool. So even with a plugin system, I think that should still be hidden behind its own "zero-configuration" tools.

What I'd like to see is a package like create-react-core pulled out into its own package. And then create-react-app has create-react-core as a dependency. It has a simple config file for things like installing specific polyfills, specifying the babel presets, any custom webpack loaders, etc. Then all you have to do to create your "zero-configuration" build tool is make a file that looks something like this:

// bin/cli.js
const cli = require('create-react-core')
const config = require('./config')
cli(config)(process.argv)

Then add that file as a bin script in your package.json and publish it. The nice thing about this is that people can create their own zero-configuration build tools for things like "create-electon-app", "create-react-lib", etc. using the "create-react-core" as the glue for everything.

In terms of the actual plugin system, if you're able to describe the entire functionality of the build tool from a single configuration object, then everything can be handled via composition :)

stereobooster commented 7 years ago

1. Automagically enable plugins based on package.json and some prefix e.g. create-react-app-* or cra-*. The same way as karma and brunch doing. Idea by @goshakkk and @just-boris. gulp doing something similar with gulp-load-plugins and grunt with load-grunt-tasks

2. Each plugin should do only one thing and do it well. UNIX philosophy. gulp doing it.

3. Ban violators of UNIX philosophy using black-list. The same way gulp doing it.

4. Most of the plugins want to modify webpack config. But some of them want to modify other files, like Jest config or flowconfig.

4.1. To modify webconfig we can use webpack-config, webpack-configurator, webpack-configurator, webpack-merge, webpack-blocks

4.2. To modify other configs we can use jscodeshift or patch

4.3. Question: is there a chance we can come up with one config format for JS tools?

5. The problem is when plugins need to know about each other. Example: SASS and CSSModules - when you want to write css in SASS but load in app in CSSModules manner. Final config will look like

loader: "style!css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass" 

Other example SASS and flowtype: you need to add to .flowconfig

module.name_mapper.extension='scss' -> '<PROJECT_ROOT>/file-stub.js'
module.name_mapper.extension='sass' -> '<PROJECT_ROOT>/file-stub.js'

SASS + Jest: '^.+\\.(css|scss|sass)$': resolve('config/jest/CSSStub.js').

SASS CSSModules flow Jest
SASS - + + +
CSSModules + - - -
flow + - -
Jest + - -

The only reasonable solution is to create one more plugin for each interaction e.g. cra-cssmodules-sass, cra-flow-sass. Use alphabetical order of components so it is cra-flow-sass, but not cra-sass-flow.

Immediate questions arise:

It is very complicated to target this problem with most general compatibility in mind. My suggestion is to start with small steps, like one project at time and see how it goes. For example SASS or CSSModules because they are popular.

Start with question: what minimal api it would take to be able to implement SASS plugin for CRA.

stereobooster commented 7 years ago

Everybody wants feature set of webpack, but don't want to get into development environment setup/configuration:

Plus a lot of people want more out of box integration with different component libraries

But to do some integrations to work out of the box sometimes you need more than current defaults. I want to get out of the box integration with react-toolbox. The reason I want it over other material design implementation for react: it is actually made out of separate components, instead of creating react wrapper around existing library (which you need to import all at once). I generally disappointed with this attitude "throw everything in". Isn't JS applications monstrous enough yet?

ccorcos commented 7 years ago

I just want to reiterate -- I like the idea of a zero-configuration build tool. So regardless of the way plugins work, I think plugins should operate outside your project itself. The only thing your project should install is your custom "zero-configuration" build tool. And that build tool uses create-react-app under the hood with some associated plugins. That way people can create zero config build tools for all sorts of different requirements or setups -- react apps, electron app, react native apps, JS libraries, etc. people and companies can have their own zero configuration build tools that fit their tastes but use create react app under the hood to do all the annoying wiring. On Sat, Oct 8, 2016 at 10:19 stereobooster notifications@github.com wrote:

Everybody wants feature set of webpack, but don't want to get into development environment setup/configuration:

using create-react-app for an app where i'm not really gonna use react b/c it's easier than setting up webpack — Thomas Boyt (@thomasABoyt) September 17, 2016 https://twitter.com/thomasABoyt/status/777217329641955328

Plus a lot of people want more out of box integration with different component libraries

Very impressed with React Storybook + Create React App integration. Documentation is coming: https://t.co/RmEGCfG6sG pic.twitter.com/jpx3b2eDff https://t.co/jpx3b2eDff — Dan Abramov (@dan_abramov) October 5, 2016 https://twitter.com/dan_abramov/status/783621896684396544

I didn’t need to configure anything. Just ran npm i -g getstorybook && getstorybook && npm run storybook. It just worked. — Dan Abramov (@dan_abramov) October 5, 2016 https://twitter.com/dan_abramov/status/783622161114300416

But to do some integrations to work out of the box sometimes you need more than current defaults. I want to get out of the box integration with react-toolbox https://github.com/react-toolbox/react-toolbox. The reason I want it over other material design implementation for react: it is actually made out of separate components, instead of creating react wrapper around existing library (which you need to import all at once). I generally disappointed with this attitude "throw everything in". Isn't JS applications monstrous enough yet?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/facebookincubator/create-react-app/issues/670#issuecomment-252436929, or mute the thread https://github.com/notifications/unsubscribe-auth/ABth33ExER-r_F_hMM5sHTKAlVZZ1tMgks5qx9C0gaJpZM4J_txI .

kitze commented 7 years ago

I like where this is going 😜

stoikerty commented 7 years ago

I think there is real value in having a plugin system that abstracts away underlying build tools such as webpack. I could very well see my dev-toolkit being superceded by a version that uses create-react-app with the necessary plugins. After all, all these create-react-app alternatives (including dev-toolkit) want to achieve a common goal. Removing as much boilerplate as possible to let us focus on creating our apps.

One of the biggest improvements going from grunt to gulp and from gulp to webpack was the ability to use more javascript, with webpack it was javascript by default. Going back to grunt-style static configuration and cli-tools with their own configs would be a big step back.

Each plugin should do only one thing and do it well. UNIX philosophy. gulp doing it.

That is one thing that gulp nailed. It was super simple to plug things together, but every now and again you had this one plugin that was so complex that nobody understood the gulp-task. I still remember the toolkit's old javascript task with browserify and watchers and whatnot. If this plugin system spawns such complexity (let alone webpack-style complexity), then I see little point in using it over using and improving webpack directly.

loader: "style!css?modules&importLoaders=1&localIdentName=[name][local]_[hash:base64:5]!postcss!sass"

personally I never want to see such config as a developer. I'd rather have a config that explains through text what it's trying to do:

import style from 'config/style';
import devEnvironment = 'config/devEnvironment';

style.cssModules = true;
if (devEnvironment === 'production'){
  style.hashedModules = true;
  style.hashType = 'base64:5'; // can be omitted for sane default
}

export style;
stereobooster commented 7 years ago

@stoikerty I'm personally not happy with this code too:

loader: "style!css?modules&importLoaders=1&localIdentName=[name][local]_[hash:base64:5]!postcss!sass"

But this is how webpack currently works. We can wrap/hide this behind code you wrote, but this is not a case as of now. Or I missing something?

stoikerty commented 7 years ago

But this is how webpack currently works. We can wrap/hide this behind code you wrote, but this is not a case as of now. Or I missing something?

My example is pseudo-code (imagining how you might configure a plugin). The main question from my point of view would be what direction the plugin system should have.

Would plugin-creators be working with exposed webpack-config from CRA? How much of webpack if any would be exposed to the developer using the plugins? What happens if webpack is replaced in the future, is this a possibility? If so, is the plugin-system still meant to work?

FezVrasta commented 7 years ago

This topic is taking a dangerous direction trying to re invent webpack 😥

stereobooster commented 7 years ago

@FezVrasta I like webpack feature set, but I don't like it's configs. I suppose I'm not the only one. It's just I have no idea (right now) how to do it better. I do not like grunt configs either. Gulp a bit better, but still not very portable across projects. I'm looking for convention over configuration approach. And CRA is great example of CoC. But I want just a pinch of configs over it.

Yes talking about reinventing webpack here would be offtopic.

FezVrasta commented 7 years ago

https://github.com/andywer/webpack-blocks

Umh?

AlicanC commented 7 years ago

https://github.com/andywer/webpack-blocks

Umh?

No, god! Please no!

The last thing we need is a system where you need plugins to do every single thing.

thien-do commented 7 years ago

Actually, I've just realized that this might put an end for https://github.com/facebookincubator/create-react-app/pull/779 (Forking react-scripts). But I'm not sure if it is better..

dceddia commented 7 years ago

I was just thinking through this problem and was about to file a separate issue when I found this one :)

I'm putting together a new project and considering starting with CRA as the foundation. As I see it, Create React App is more than just a "starter" tool -- it's about turning build configuration into a black-box dependency. This seems really exciting to me, because it means I can focus on writing features but still benefit from the latest the community has to offer in terms of build + project infrastructure.

In past projects that used Grunt and then Gulp, we had the problem that we'd setup a build, forget all the details, and go about our days... until some point later when some awesome new thing came out, or the community switched gears, or the build got too slow, and then we'd need to decide between retooling or leaving it alone. Usually, there was more pressing work to do than rewrite the build.

The option of forking react-scripts (#779) is the only tool for customization at the moment, and while it does work, it seems a bit "heavy" to me. It requires keeping the fork up to date (if done in-house), or relying on the package maintainer to do so. It takes on more maintenance baggage than it needs to.

A simple plugin system seems like a nice solution for this, because it keeps all the gory details of Webpack (et al) away from the end user while still allowing them to use pre-built plugins (or, if they want to dive in, write a plugin themselves) to influence the configuration.

I created a POC in a pull request here (https://github.com/facebookincubator/create-react-app/pull/979) -- see comments there for how it works. It's pretty simple and minimally invasive.

AlicanC commented 7 years ago

The option of forking react-scripts (#779) is the only tool for customization at the moment, and while it does work, it seems a bit "heavy" to me. It requires keeping the fork up to date (if done in-house), or relying on the package maintainer to do so. It takes on more maintenance baggage than it needs to.

It's not that bad. Some of our projects use year old build systems and they work just fine. Good software shouldn't need constant updates so don't think like you will have to sync with upstream every week.

dceddia commented 7 years ago

It's not that bad. Some of our projects use year old build systems and they work just fine.

Do you mean forking/updating in general? CRA has only been out about 3 months but has had a lot of changes and advancements over its 28 releases. I guess keeping up with a fork isn't all that bad but avoiding it seems even better.

AlicanC commented 7 years ago

Do you mean forking/updating in general?

I mean CRA. I don't see an option for not keeping a fork here.

With plugins, you have to keep a repository of your plugins anyways. Plus you have to create a plugin to make a change. This puts you in the same plugin-hell that Grunt and Gulp are in.

Without plugins, you just fork "react-scripts" and hack whatever files you need to. If you see something cool on upstream, you can merge.

ccorcos commented 7 years ago

Without plugins, you just fork "react-scripts" and hack whatever files you need to. If you see something cool on upstream, you can merge.

Yeah, but that assumes an upstream merge is going to become merge conflict hell.

I'm with @dceddia -- a very simple plugin system (just piping a webpack config through various functions) would make things much easier. Even if you had to fork react-scripts, if it was written in this sort of way, upstream merges should be a lot easier...

timarney commented 7 years ago

Just tossing this into the conversation.

I built this when create-react-app first came out - https://github.com/timarney/react-app-rewired

It's a hack but it's pretty flexible

It basically loads the config from react-scripts and allows overriding

see https://github.com/timarney/react-app-rewired/blob/master/scripts/start.js

var defaults = rewire('react-scripts/scripts/start.js')
var config = defaults.__get__('config')

config = override(config)

// override the default
defaults.__set__('config', config)
defaults.__get__('run')(port)

@AnthonySapp - used the idea to create a boilerplate with Sass + TypeScript

https://github.com/campjefferson/react-typescript-app-boilerplate/blob/master/node_scripts/config-overrides.js

No fork of react-scripts just having access to the config to allow overrides

AlicanC commented 7 years ago

@ccorcos

Yeah, but that assumes an upstream merge is going to become merge conflict hell.

Why "hell"? You are just modifying two Webpack configs.

If you are talking about modifying more than that, you are still at advantage because without forking you wouldn't be able to that at all.

I'm with @dceddia -- a very simple plugin system (just piping a webpack config through various functions) would make things much easier.

I am not against the idea of a very simple plugin system. It is just not that simple.

Imagine this plugin:

export default (config, paths) => {
  config.resolve.alias.app = paths.appSrc;
};

Currently, this is what webpack.config.dev.jss relevant part looks like:

module.exports = {
  /* ... */
  resolve: {
    /* ... */
    alias: {
      'react-native': 'react-native-web'
    }
  },
  /* ... */
};

If CRA decides to not alias "react-native-web" and removes config.resolve.alias completely, the plugin above will start to throw. A plugin system like this basically makes any touch on default Webpack config a breaking change. I don't think that's okay.

If you start covering these cases, the system stops being simple.

dceddia commented 7 years ago

A plugin system like this basically makes any touch on default Webpack config a breaking change.

I think that's the advantage of having versioned plugins though, because the plugins could specify "I work with CRA 0.7.0" and if those versions change, you get an error at npm/yarn install time and not at runtime. It's not great though, I agree.

That particular case could be worked around -- maybe the plugin system could wrap the plugin calls in a try/catch and just discard that plugin's changes -- but I get your point.

I do also worry a bit about causing a "plugin-hell" ecosystem like Grunt and Gulp have. I don't think this is quite the same case though, because CRA has many sane defaults while Grunt and Gulp run configs that are built from the ground up with plugins. Plugins are in their blood. You can't get much done without them. On the other hand, CRA works quite well on its own.

@timarney I really like your solution. In fact I tried something like that at first, but I didn't know about rewire so I was doing some crazyness with vm and attempting to run the file as a script and it... didn't really work. It's hacky, yeah, but it feels cleaner and less maintenance-prone than forking. I'm happy doing something like that if plugins aren't meant to be. As long as I get to keep all the CRA goodness!

oyeanuj commented 7 years ago

Also worth pointing out a system like Slate (https://github.com/ianstormtaylor/slate) where even the core is essentially a plugin as well, and could work as an alternative to scheme proposed in https://github.com/facebookincubator/create-react-app/issues/670#issuecomment-247839570.

jkarttunen commented 7 years ago

What if there was a 'create-web-app with plugins' project, and 'create-react-app' was that with basic react plugin.This would let people do other cool stuff too. (I'm just working on a d3 app starter for a friend, basing it on create-react-app project, just getting rid of react :(

stereobooster commented 7 years ago

@jkarttunen using CRA because don't want to configure Webpack? Seen before. But there are also different zero-config development servers, like budo

jkarttunen commented 7 years ago

More like I like how the webpack is configured here

ccorcos commented 7 years ago

Over the holidays, I was messing around and came up with a project that hopes to solve this whole forking problem. It's a pattern for building tools like create-react-app in such a way that makes them easy to be extended without npm dependencies. I'm curious to hear any of your thoughts:

https://github.com/ccorcos/doug

Hurtak commented 7 years ago

How about instead of plugin system we let users extend the webpack config, something that https://github.com/palmerhq/backpack#customizing-webpack is doing

// backpack.config.js
module.exports = {
  webpack: (config, options) => {
    // Perform customizations to config
    // Important: return the modified config
    return config
  }
}
timarney commented 7 years ago

@Hurtak Doing that here already https://github.com/timarney/react-app-rewired @gaearon has been very clear with pitfalls with doing this namely https://github.com/facebookincubator/create-react-app/issues/99#issuecomment-234657710 (see other refs in that ticket).

In the react-app-rewired repo there are some 'pre-wired configs which kind of work around this but yes people could still mess them up. https://github.com/timarney/react-app-rewired/tree/master/packages/react-app-rewire-preact

deepak commented 7 years ago

would love to create an React + Electron app with CRA webpack supports 2 Electron targets

had asked the same question on the atom board but it more of a wishlist

was pointed to ember-electron, not sure if that helps

davidnguyen11 commented 7 years ago

If it could support. We could added custom plugins like: Offline, Testing, ... I think it would be more flexible for developing app. It would be nice if you open api for this case.

PavelPolyakov commented 7 years ago

Hi,

Just started to use create-react-app more or less regularly and I feel myself missing to throw several babel plugins into the configuration, like this:

plugins: ['transform-decorators-legacy','react-html-attrs'],

For one of the app I did the eject, however, I was overwhelmed with the amounts of the ejected files. Before I was playing with Nuxt and must say I liked the idea of the possible configuration provided there (https://nuxtjs.org/api/configuration-build).

I would vote for any concept of the extending the default configuration without EJECTING all of it.

@gaearon As the suggestion, what would you say, in case the values from the projects .babelrc would actually overwrite (or being merged with) the default create-react-app babel configuration, for example? In case this suggestion is accepted, at least in theory, I can work on the pull request regarding this.

tuchk4 commented 7 years ago

@PavelPolyakov I've already provide such PR https://github.com/facebookincubator/create-react-app/pull/1357 but:

And possible future for app with experimental features:

Imagine the horror of building / maintaining an app that relies on dead syntax features five years from now. (https://twitter.com/dan_abramov/status/818627079306694658)

Making "eject" you donate all of the all new CRA features in order to add custom babel plugins or update webpack conf (in most cases such update is a few lines of code).


webpack / babel and any other configuration will make CRA very fragile. And CRA team cannot guarantee perfect experience and stability. And possible result - million issues at CRA repo that are not related to CRA.

tuchk4 commented 7 years ago

While updating Awesome CRA found react-scripts version that supports plugins - https://github.com/thtliife/create-react-app/tree/react-scripts-pluggable/packages/react-scripts

Seems relate to this thread

PavelPolyakov commented 7 years ago

@tuchk4 Thanks, interesting, would play with those pluggables then!

PavelPolyakov commented 7 years ago

@tuchk4 I've explored the react-scripts-pluggable and can not consider to use this, because:

  1. it's far from official
  2. I've found out, that the webpack config which is received by the pluggable plugin has little correlation with the one which I receive during the eject
  3. basically using this pluggable solution is the same as doing eject - as you said:

    Making "eject" you donate all of the all new CRA features in order to add custom babel plugins or update webpack conf (in most cases such update is a few lines of code).

at the end, I still think that there should be a solution when you do not need to refuse from the CRA feature, but, at the same time is able to configure webpack a little. Obviously, if you do anything on your own fear - you do not expect that community is responsible for your changes.

thtliife commented 7 years ago

@tuchk4 Thanks for mentioning react-scripts-pluggable :)

@PavelPolyakov Thanks for the feedback on react-scripts-pluggable :) I have addressed a couple of things in the latest version.

  1. It still is far from official, although it is maintained as a fork of the official create-react-app, and I endeavour to keep the fork as up to date as possible, inline with updates from the upstream repo.

  2. I have resolved the issue with eject, and now pluggable plugins work whether ejected or not. (However the idea is to allow plugins without needing to eject...) ;)

  3. It is not the same as doing an eject. The scripts are unchanged except for wrapping the call to webpack.environment.config.js in a function which receives the original webpack config, and allows a pluggable-plugin to modify it enough to inject the plugin, then return it back to the start.js script. (There is also a small change in the eject.js script to ensure it copies the pluginWrapper.js to the ejected config folder.

The entire idea is to allow adding webpack plugins in the same zero-config manner as create-react-app is designed upon.

As an example, try the following to add sass support to your cra project:

create-react-app test-project --scripts-version react-scripts-pluggable
cd test-project
npm install --save pluggable-sass-loader

rename src/index.css to index.scss and replace its content with:

$font-stack: sans-serif;
$background: #222;

body {
  margin: 0;
  padding: 0;
  font-family: $font-stack;
}

.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 80px;
}

.App-header {
  background-color: $background;
  height: 150px;
  padding: 20px;
  color: white;
}

.App-intro {
  font-size: large;
}

@keyframes App-logo-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

Now in src/index.js, change line 4 from:

import './index.css';

to:

import './index.scss';

The idea is that you use the plugins, (As they are developed), to enable features with zero config required. Same as how create-react-app allows to build React apps on webpack with zero config required.