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

"extract-text-webpack-plugin" loader is used without the corresponding plugin #579

Closed
digitalkaoz opened this issue Feb 1, 2017 · 46 comments
Labels

Comments

@digitalkaoz
Copy link

digitalkaoz commented Feb 1, 2017

Again, this error popped up (node-version: v7.4.0)

ERROR in ./style/index.scss
    Module build failed: Error: "extract-text-webpack-plugin" loader is used without the corresponding plugin, refer to https://github.com/webpack/extract-text-webpack-plugin for the usage example
        at Object.module.exports.pitch (/project/node_modules/extract-text-webpack-plugin/loader.js:27:9)
     @ ./js/components/App.jsx 8:0-34
     @ ./~/html-webpack-plugin/lib/loader.js!./js/index.jsx
{
  "devDependencies": {
    "extract-text-webpack-plugin": "^2.0.0-rc",
    "html-webpack-plugin": "^2.28.0",
    "webpack": "2.2.0",
  }
}

my webpack config

const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: ['./js/index.jsx'],

    module: {
        loaders: [
            {
                test: /\.scss$/,
                loader: ExtractTextPlugin.extract({
                     fallbackLoader: 'style-loader',
                     loader: ['css-loader', 'sass-loader']
                 })
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './js/index.jsx',
            inject: false
        }),
        new ExtractTextPlugin({filename: '[name].css', allChunks: true}),
    ]
};

my template

import React from 'react';
import { render } from 'react-dom';
import { renderToString } from 'react-dom/server';

import App from './components/App.jsx';

class Html extends React.Component {
    render() {
        return <html lang="en">
        <head>
            <meta charSet="utf-8"/>
            <link rel="stylesheet" href="/main.css"/>
        </head>
        <body>
        <App />
        <script async defer src="/bundle.js"></script>
        </body>
        </html>
    }
}


// Client render (optional):
if (typeof document !== 'undefined') {
     render(<Html/>, document);
}

// Exported static site renderer:
export default (locals, callback) => {
    const html = '<!DOCTYPE html>'+ renderToString(<Html {...locals} />);

    //server side rendering
    if ('function' === typeof callback) {
        callback(null, html);
    } else {
        //html-webpack-plugin
        return html;
    }
};

if i exclude the ExtractTextPlugin the rendering works fine...

any ideas?

@jantimon
Copy link
Owner

jantimon commented Feb 1, 2017

Wow I am really impressed that you found out how to use this plugin for server side rendering.

There is no documentation at all for this feature (although it was developed over a year ago).

There are/were several webpack bugs which didn't get enough priority by the webpack core team:

  1. Extract Text Plugin does not work (Compilation fails with extract-text-webpack-plugin #201)
  2. __dirname does not work (master/lib/NodeStuffPlugin.js does not work when used in child compiler webpack/webpack#2978)
  3. __file does not work (master/lib/NodeStuffPlugin.js does not work when used in child compiler webpack/webpack#2978)
  4. no way to define different globals for frontend / server side rendering (Webpack DefinePlugin bleeds from child compilation into main compilation webpack/webpack#2979)

As I always thought of this feature as a nice to have I stopped working on it.
Maybe we could ask @bebraw if we should pick up this topic again - now that webpack 2 got released and the webpack core team grew a lot.

@digitalkaoz
Copy link
Author

Well it has nothing todo with SSR. I even dont use it in case of SSR because another plugin handles the generation of the index.html . Only use it for providing the index.html in dev Mode.

So the problem is somewhere else...

@bebraw
Copy link

bebraw commented Feb 2, 2017

@digitalkaoz Can you set up a standalone project to study?

@bebraw
Copy link

bebraw commented Feb 2, 2017

@digitalkaoz Instead of loader: ExtractTextPlugin.extract I would go with use: ExtractTextPlugin.extract.

@jantimon
Copy link
Owner

jantimon commented Feb 2, 2017

new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './js/index.jsx',
            inject: false
        }),

is rendered at build time not in browser - so this is server side rendering ;)

@bebraw thanks for picking this up 👍

@sokra
Copy link
Contributor

sokra commented Feb 2, 2017

We could establish a new term for this: CTR (Compile-Time Rendering) 😉

@jantimon
Copy link
Owner

jantimon commented Feb 2, 2017

@sokra Haha unfortunately ctr is already used :)

This feature could boost the initial perceived load time of many react apps a lot without much work for the developer.

@markdalgleish built a plugin which also uses webpack to render at buit time https://github.com/markdalgleish/static-site-generator-webpack-plugin
See his talk at reactive conf on that topic https://www.youtube.com/watch?v=ovIrOMBbWrc

I added an example for this a while back: https://github.com/jantimon/html-webpack-plugin/tree/master/examples/javascript

To get the same error like @digitalkaoz just add a require statement to a css file in https://github.com/jantimon/html-webpack-plugin/blob/master/examples/javascript/universial.js

@pirelenito also created a unit test for the extract-text-webpack-plugin in pr #201 (1 year ago for webpack 1)

@sokra
Copy link
Contributor

sokra commented Feb 2, 2017

BTR: Build-Time Rendering?

@mdnsk
Copy link

mdnsk commented Feb 2, 2017

Hi there! I have the same issue.
My webpack.config.js:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')

module.exports = {
  entry: './index.js',

  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },

  module: {
    loaders: [
      {
        test: /\.ejs$/,
        loader: 'ejs-loader'
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: 'css-loader'
        })
      }
    ]
  },

  plugins: [
    new HtmlWebpackPlugin({
      title: 'My App',
      template: 'index.ejs'
    }),

    new ExtractTextPlugin({
      filename: "css/[name].css?[hash]-[chunkhash]-[contenthash]-[name]",
      disable: false,
      allChunks: true
    })
  ]
}

index.ejs:

<html>
    <head>
        <% require('./style.css') %>
    </head>
    <body>
        <h1>It works</h1>
    </body>
</html>

If I remove <% require('./style.css') %>, it works fine.

@bebraw
Copy link

bebraw commented Feb 2, 2017

@mdnsk Yeah, after removing <% require('./style.css') %> it won't trigger extract-text-plugin logic. The question is, why does it fail to wire it up properly in this case.

@digitalkaoz
Copy link
Author

@jantimon but there was no resolution #201
@bebraw using use instead of loader doesnt change anything

here is the example project which causes this bug:

https://github.com/digitalkaoz/digitalkaoz.github.io/tree/html_webpack

but as @jantimon stated, just require a css file in your JS to trigger the bug... im a bit confused as it looks like it works in the provided examples in this repo (but its using webpack1)?!

@mdnsk
Copy link

mdnsk commented Feb 2, 2017

@bebraw

The question is, why does it fail to wire it up properly in this case.

I mean the same question. I need it to use in my partial ejs templates. For example, components/header/header.ejs:

<% require('./header.css') %>

<header class="<%- classes.join(' ') %>">
    It is header.

    <%= require('../nav-menu/nav-menu.ejs')({classes: ['header__menu']}) %>
</header>

@bebraw
Copy link

bebraw commented Feb 2, 2017

@mdnsk Yup. That was more of a question which we should study. I have to get a little demo up and running to say anything more.

@sokra
Copy link
Contributor

sokra commented Feb 2, 2017

The problem is require to styles in a html-plugin template.

What you want it probably to specify other module.rules for css in the child compilation. i. e. use the null-loader while rendering the html-plugin template. But this is not possible currently.

One possible solution is the add a rule condition for compilation name.

{
  test: /\.css$/,
  oneOf: [
    { compilation: /html-webpack-plugin/, use: "null-loader" },
    { use: ETP. ... }
  ]
}

@digitalkaoz
Copy link
Author

@bebraw you can use the examples in this repo:

To get the same error like @digitalkaoz just add a require statement to a css file in https://github.com/jantimon/html-webpack-plugin/blob/master/examples/javascript/universial.js

@jantimon
Copy link
Owner

jantimon commented Feb 2, 2017

The root problem is that the extract text plugin uses kind of a hack to communicate between loader and plugin. (See here https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/master/index.js#L216-L227 and here https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/master/loader.js#L26)
This hack works only in the main compilation however the html-webpack-plugin is using a child compilation.

The null loader seems to be a work a round - imho we should add a feature request for the extract-text-plugin to support child compilations.

This might add a feature request for the webpack core (easier communication between loaders and plugins)

@digitalkaoz thanks - we understood that - #201 shows the problem but has no solution to the problem as it can't be solved in the html-webpack-plugin.

@digitalkaoz
Copy link
Author

as @bebraw seems active in both projects he seems to be the right person to investigate :)

@bebraw
Copy link

bebraw commented Feb 2, 2017

@digitalkaoz Tobias likely knows this area the best. By the sound of it, it's going to require a bigger change to pull this off properly. The way extract-text-plugin handles communication is the problem and that would have to change in order to fix this. Perhaps a plugin/loader should know something about its compilation context so it doesn't default to the root one?

@digitalkaoz
Copy link
Author

@sokra the compilation seems not existing on Rule options... https://webpack.js.org/configuration/module/#rule or am i missing something?

can you provide a correct example to me?

@bebraw
Copy link

bebraw commented Feb 2, 2017

@digitalkaoz That was a potential solution that needs to be implemented still. compilation field doesn't exist yet.

@jantimon
Copy link
Owner

jantimon commented Feb 2, 2017

Maybe we can move this part of the discussion to the extract-text-webpack-plugin:
webpack-contrib/extract-text-webpack-plugin#389

@digitalkaoz
Copy link
Author

digitalkaoz commented Feb 2, 2017

ok, i have it working somehow:

everything depends on this patch: webpack-contrib/extract-text-webpack-plugin#390

thanks @sokra for the hint on Rules!

webpack.config.js

{
    module: {
        rules: [
            {
                test: /\.scss$/,
                oneOf: [
                    {test: /html-webpack-plugin/, use: "null-loader"},
                    {
                        use: ExtractTextPlugin.extract({
                            fallbackLoader: 'style-loader',
                            loader: ['css-loader', 'sass-loader']
                        })
                    }
                ]
            },
       ],
   },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './js/index.jsx',
        }),
        new ExtractTextPlugin({filename: '[name].css'}),
    ]
}

index.jsx

import React from 'react';
import Document from './components/Document.jsx';

const styles = [];
const scripts = [];

// Client Rendering
if (typeof document !== 'undefined') {
    const Dom = require('react-dom');
    const App = require('./components/App.jsx').default; //lazy because of window dep

    Dom.render(<App />, document.getElementById('app'));
}

export default (locals, callback) => {
    const Server = require('react-dom/server');

    // Serverside Rendering
    if ('function' === typeof callback) {
        const App = require('./components/App.jsx').default; //render the full app

        callback(null, '<!DOCTYPE html>'+ Server.renderToString(<Document app={<App />} scripts={ scripts } styles={ styles }/>));
    } else {
        // Build-Time Rendering
        return '<!DOCTYPE html>'+ Server.renderToStaticMarkup(<Document />);
    }
};

Document.jsx

import React from 'react';

export default class extends React.Component {

    static defaultProps = {
        scripts: [],
        styles: [],
        app: null
    };

    render() {
        return <html lang="en">
        <head>
            { this.props.styles.map((s) =>{ return <link rel="stylesheet" key={s} href={s} type="text/css" /> })}
        </head>
        <body>
        <div id="app">{ this.props.app }</div>
        { this.props.scripts.map((s) =>{ return <script key={s} src={s}></script> })}
        </body>
        </html>
    }
}

@mdnsk
Copy link

mdnsk commented Feb 3, 2017

Thank you @digitalkaoz and @sokra ! I have it working now.
Also I've added my ejs templates to the entry property to gather css dependencies of all the templates:

  entry: {
    'bundle': './index.js',
    '__page-index': './pages/index.ejs',
    '__page-contacts': './pages/contacts.ejs'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
...
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Index Page',
      filename: 'index.html',
      template: './pages/index.ejs'
    }),

    new HtmlWebpackPlugin({
      title: 'Contacts Page',
      filename: 'contacts.html',
      template: './pages/contacts.ejs'
    }),

    new ExtractTextPlugin('style.css')
  ]

@GeekaholicLin
Copy link

@mdnsk ExtractTextPlugin works when adding templates as entry.However,it seems the link tags are not inserted automatically.Have you figured it out?

@ekil1100
Copy link

ekil1100 commented Jun 6, 2017

It still doesn't work in my project @mdnsk
The project repo:
https://github.com/lastingman/webpack-project.git

@kirschkern
Copy link

After struggeling for 3 days with this issue, I've found out, that I only get it when using the terminal plugin in my Atom editor. When running "npm run dev" from the windows cmd app, it works fine.

Hope this is of any help for others.

@bebraw
Copy link

bebraw commented Jun 7, 2017

@kirschkern Can you provide more information? Do you understand why Atom breaks it?

@kirschkern
Copy link

Sorry, I have no idea why it doesn't work from inside the terminal plugin. I can only offer this "workaround" so far.
Terminal plugin is: https://github.com/platformio/platformio-atom-ide-terminal

@huangshuwei
Copy link

the same issue.

This is my environment:
webpack 3.0.0
html-webpack-plugin 2.29.0
extract-text-webpack-plugin 2.1.2

When i added extract-text-webpack-plugin, It's fine

// webpack.config.js
var ExtractTextPlugin = require('extract-text-webpack-plugin');

{
 module: {
            rules: [
                    // css loader
                   {
                      test: /\.css$/,
                      use:  ['style-loader', 'css-loader']
                  }
            ]
 },
 plugins:[
    new ExtractTextPlugin('css/[name]-[contenthash:8].css')
 ]
}

@HosseinAgha
Copy link

HosseinAgha commented Jul 26, 2017

I couldn't find the solution for using this plugin alongside extractTextPlugin. Adding the template to entries doesn't seem like a good solution for me.

@mastilver
Copy link
Collaborator

mastilver commented Jul 26, 2017

@HosseinAgha your issue is not related to the above, please open a new issue or ask your question on stackoverflow, in the meantime, check this simple example: https://github.com/jantimon/html-webpack-plugin/blob/master/examples/javascript/webpack.config.js

@HosseinAgha
Copy link

HosseinAgha commented Jul 26, 2017

@mastilver thank you for your response.
I think I have the same issue here. As I understand what everybody want to do here is generating html statically using html-webpack-plugin and using css inside templates then extract all required css modules as a separate file.
I want to do this because I want to have a light compile time rendered page that eventually loads my main bundle.
I want html-webpack-plugin to generate the final html using my template because I use chunkhash for caching my js files so I need a plugin to inject files to it.
So correct me if I'm wrong. I don't think I can achieve above with a plugin like static-site-generator-webpack-plugin.

@sokra
Copy link
Contributor

sokra commented Jul 27, 2017

btw. you can configure different loaders depending on compilation:

rules: [
  {
    test: /\.css$/,
    compiler: { not: /^html-webpack-plugin/ },
    use: ExtractTextPlugin.extract(...)
  }
]

@HosseinAgha
Copy link

HosseinAgha commented Jul 29, 2017

@sokra This throws an error for me seems like webpack 2.7.0 does not understand compiler: not: RegExp option. The outputs is:

Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration.module.rules[8].compiler should be one of these:
RegExp | non-empty string | function | [(recursive)] | object { and?, exclude?, include?, not?, or?, test? }

And I use this rule

       test: /\.styl$/,
       compiler: {
         not: /^html-webpack-plugin/
       },
       use: ExtractTextPlugin.extract({
         fallback: 'style-loader',
         use: [
            {
             loader: 'css-loader',
             options: {
               modules: true,
               localIdentName: '[emoji]_[path]_[name]_[local]_[hash:base64:3]'
             }
            }, 
            { loader: 'stylus-loader' }
         ]

@LiuYashion
Copy link

share a correct way~

module: {
    rules: [
        {
            test: /\.css$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: [{
                        loader: 'css-loader',
                        options: {
                            importLoaders: 1,
                        }
                    },{
                        loader: 'postcss-loader',
                        options: {           
                            plugins: (loader) => [precss, autoprefixer({
                                browsers: [
                                    "> 1%",
                                    "last 5 versions",
                                    "ie 6"
                                ]
                            })]
                        }
                    }
                ]
            })
        }
    ]
},

plugins:[
    // ...
    new ExtractTextPlugin('[name]/styles.[contenthash].css')
],

@Maseeharazzack
Copy link

Finally what is the right answer?

@izverev-aexsoft
Copy link

I've never seen more counter-intuitive and error-prone thing then webpack.config... cannot do single bit without running into mysterious issues and googling around for hours. There is no plugin once you just added the plugin... enough for today

@joscha
Copy link

joscha commented Jul 26, 2018

I am still waiting for this to be fixed :(

@stale stale bot removed the wontfix label Jul 26, 2018
@kingda
Copy link

kingda commented Jul 27, 2018

So....what is the right answer? @digitalkaoz

Repository owner deleted a comment from stale bot Jul 27, 2018
@jantimon
Copy link
Owner

It's the same as webpack-contrib/mini-css-extract-plugin#219

The html-webpack-plugin picks up the main compiler configuration but the mini-css-extract-plugin and the extract-text-plugin loaders get confused somehow.

It's probably because of the way the loader and plugin communicate using the this[ns] hack.

@kingda
Copy link

kingda commented Jul 29, 2018

@jantimon do u have some ways to filter html-webpack-plugin not to handle with mini-css-extract-plugin loader ? I have tried some ways from above but it was still not work well .

@evenlone
Copy link

evenlone commented Aug 7, 2018

https://blog.csdn.net/simplehouse/article/details/78408679
I solved this problem with this statement $env:NODE_ENV="development"
1
It should be a bug of Atom package: platformio-ide-terminal ,cause windows cmd app works.
Add the statement in this package setting -> Core -> Auto Run Command

@digitalkaoz
Copy link
Author

anyone searching for a solution, this is the right one:

drop this plugin and do it with the extract-loader + file-loader:

webpack-contrib/extract-text-webpack-plugin#50 (comment)

@donaldpipowitch
Copy link

@digitalkaoz Thank you for the workaround. Using extract-loader + file-loader seems to prevent the error and a CSS files is generated, but it looks like this file isn't added automatically to my index.html inside <head>.

@susan007
Copy link

susan007 commented Apr 9, 2019

finally i am ok!when i add

fallback:'style-loader'

use: ExtractTextWebpackPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })

@stale
Copy link

stale bot commented Oct 6, 2019

This issue had no activity for at least half a year. It's subject to automatic issue closing if there is no activity in the next 15 days.

@stale stale bot added the wontfix label Oct 6, 2019
@stale stale bot closed this as completed Oct 21, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Nov 20, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests