Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin System #670

Closed
gaearon opened this issue Sep 17, 2016 · 55 comments
Closed

Plugin System #670

gaearon opened this issue Sep 17, 2016 · 55 comments

Comments

@gaearon
Copy link
Contributor

gaearon commented Sep 17, 2016

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
Copy link
Contributor

just-boris commented Sep 17, 2016

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
Copy link

arturparkhisenko commented Sep 17, 2016

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
Copy link
Contributor

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
Copy link
Contributor

goshacmd commented Sep 18, 2016

@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
Copy link

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
Copy link
Contributor

@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
Copy link

@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
Copy link

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
Copy link

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
Copy link
Contributor Author

gaearon commented Sep 18, 2016

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
Copy link

AlicanC commented Sep 18, 2016

@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
Copy link

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
Copy link

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

@insin
Copy link
Contributor

insin commented Sep 19, 2016

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: 344893b

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
Copy link

ccorcos commented Sep 20, 2016

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
Copy link
Contributor

stereobooster commented Oct 8, 2016

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:

  • How do you discover those interaction plugins?
  • Who will be responsible for supporting them?
  • Is there case when you need to account interaction of more than two plugins simultaneously?

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
Copy link
Contributor

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

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

— Dan Abramov (@dan_abramov) October 5, 2016

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

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
Copy link

ccorcos commented Oct 8, 2016

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
#670 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABth33ExER-r_F_hMM5sHTKAlVZZ1tMgks5qx9C0gaJpZM4J_txI
.

@kitze
Copy link

kitze commented Oct 8, 2016

I like where this is going 😜

@stoikerty
Copy link
Contributor

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
Copy link
Contributor

@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
Copy link
Contributor

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
Copy link
Contributor

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

@stereobooster
Copy link
Contributor

@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
Copy link
Contributor

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

Umh?

@AlicanC
Copy link

AlicanC commented Oct 13, 2016

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
Copy link
Contributor

thien-do commented Oct 14, 2016

Actually, I've just realized that this might put an end for #779 (Forking react-scripts). But I'm not sure if it is better..

@timarney
Copy link

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
Copy link

AlicanC commented Oct 29, 2016

@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
Copy link
Contributor

dceddia commented Oct 29, 2016

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
Copy link

oyeanuj commented Oct 30, 2016

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 #670 (comment).

@jkarttunen
Copy link

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
Copy link
Contributor

stereobooster commented Nov 23, 2016

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

@jkarttunen
Copy link

More like I like how the webpack is configured here

@ccorcos
Copy link

ccorcos commented Dec 1, 2016

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
Copy link
Contributor

Hurtak commented Jan 14, 2017

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
Copy link

timarney commented Jan 14, 2017

@Hurtak Doing that here already https://github.com/timarney/react-app-rewired @gaearon has been very clear with pitfalls with doing this namely #99 (comment) (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
Copy link

deepak commented Jan 20, 2017

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
Copy link

davidnguyen11 commented Jan 24, 2017

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
Copy link

PavelPolyakov commented Feb 19, 2017

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
Copy link
Contributor

tuchk4 commented Feb 20, 2017

@PavelPolyakov I've already provide such PR #1357 but:

  • as soon as feature becomes candidate - CRA will support it. Here is tweet about decorators.
  • features from stages 0 - 2 are not support because a lot of them hasn't been updated in a long time and doesn't appear to progress.

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
Copy link
Contributor

tuchk4 commented Feb 20, 2017

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
Copy link

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

@PavelPolyakov
Copy link

@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
Copy link

thtliife commented Mar 9, 2017

@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.

@thtliife
Copy link

thtliife commented Mar 9, 2017

Oh also... @gaearon
In response to the original question

If Create React App had a plugin system, what would it be like?

Check out my take on a plugin system for create-react-app based on the 0.9.x branch as per your comment #779 (comment)

We care about experience of forkers, and if there's more things we should fix, please file issues. The only gotcha right now is that we're releasing from 0.9.x branch since Webpack integration in master still has issues. So we recommend releasing based on 0.9.x as well.

react-scripts-pluggable
Github link (It is the react-scripts-pluggable branch of the fork).

@sheerun
Copy link
Contributor

sheerun commented Mar 12, 2017

Neutrino has concept of presets that are simple node.js modules implementing function transforming its configuration. Notably it allows for configuring webpack configuration by modifying neutrino.config that is an instance of webpack-chain

I wish create-react-app adapted similar approach :)

@gaearon
Copy link
Contributor Author

gaearon commented Apr 22, 2017

Wrote up a little tweetstorm here if you're interested: https://twitter.com/dan_abramov/status/855843921385201664

I agree about Neutrino's approach being nice (you can use one preset at a time, right?)

@davidnguyen11
Copy link

davidnguyen11 commented Apr 23, 2017

You might want to take a look at next.js public webpack config. I think it is a great way.

@gaearon
Copy link
Contributor Author

gaearon commented Jan 8, 2018

There are no plans to do this right now. If you're interested in more flexibility, check out Neutrino.

@gaearon gaearon closed this as completed Jan 8, 2018
@timarney timarney mentioned this issue Aug 9, 2018
@lock lock bot locked and limited conversation to collaborators Jan 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests