peerigon / extract-loader

webpack loader to extract HTML and CSS from the bundle
The Unlicense
317 stars 73 forks source link

Support extract jade ? #10

Open woohling opened 7 years ago

woohling commented 7 years ago

I'm using Jade, and can I compile my index.jade to index.html then extract it ? Here's my trial but failed: var indexHtml = __dirname + '/src/views/index.html'; { test: indexHtml, loaders: [ "file?name=[name].[ext]", "extract", "html", "jade" ] } Any Help? Many thanks ~

jhnns commented 7 years ago

That should work – provided that you included the index.html anywhere in your bundle.

jpommerening commented 7 years ago

Late to the party, but: The jade-loader (as well as the pug-loader that replaced it) returns a template function that you have to call with the template substitutions you want to make. (See above links.)

The HTML loader expects a string of HTML as input, so it's not able to process the result (which is JavaScript code).

You can use the apply-loader to call the template function and export the HTML result.

Also, you need to test for the input file (is index.html or index.jade?). I'm not really sure about the absolute path (__dirname), you might just want to use a regex like /\.jade$/ or /\.html$/.

Example:

// webpack config module.loaders:
{
  test: /\.jade$/,
  loaders: [ "file?name=[name].html", "extract", "html", "apply", "jade" ]
}
// your code:
const htmlUrl = require( './views/index.jade' );
jhnns commented 7 years ago

@jpommerening Wow, that's genius. Would you be open to add a test/example for that to the extract-loader? :D

markbrouch commented 7 years ago

Very late to the party 😄

@jpommerening This was the solution I came up with as well, but it doesn't seem to be working. I was wondering if you could take a look to see if I'm missing something obvious.

My webpack config module.loaders:

{
  test: /\.pug$/,
  loaders: [
    {
      loader: 'file-loader',
      options: { name: '[path][name].html' }
    },
    'extract-loader',
    'html-loader',
    'apply-loader',
    'pug-loader'
  ]
}

This generates the correct html files, but their contents are off. For instance, each html file will be something like:

var req = require("!!<absolute-path-to-project>/node_modules/pug-loader/index.js!<absolute-path-to-pug-file>/a.pug");
module.exports = (req['default'] || req).apply(req, [])

...instead of the expected HTML.

I've tried a similar setup with extract-text-webpack-plugin in conjunction with pug-loader and apply-loader and that worked except for how the plugin combines all files into one (I want them separate for pug). It seems like the issue is with extract-loader not running the apply-loader's exported function (which should be the html from the pug template function).

Removing html-loader from the loader pipeline results in a webpack error:

ERROR in ./index.pug
Module build failed: <absolute-path-to-pug-file>/index.pug:2
module.exports = (req['default'] || req).apply(req, [])
                                         ^

TypeError: (req.default || req).apply is not a function

Greatly appreciate some help!

zxdong262 commented 6 years ago

I've tried a similar setup with extract-text-webpack-plugin in conjunction with pug-loader and apply-loader and that worked

@markbrouch will you please share this config?

battlesnake commented 6 years ago

@markbrouch : I have the same issue (or similar at least), did you ever resolve it?

Pug rule:

            {
                test: /\.pug$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[path][name].html'
                        }
                    },
                    {
                        loader: 'extract-loader'
                    },
                    {
                        loader: 'html-loader',
                        options: {
                            basedir: resolve('src'),
                            attrs: [
                                'img:src',
                                'a:href',
                                'script:src',
                                'link:href'
                            ],
                            root: resolve('src')
                        }
                    },
                    {
                        loader: 'apply-loader',
                        options: {
                            obj: {
                                pages: require('./src/page'),
                                products: require('./src/product'),
                            }
                        }
                    },
                    {
                        loader: 'pug-loader',
                        options: {
                            basedir: resolve('src'),
                            pretty: true
                        }
                    }
                ]
            },

Other stuff:

const resolve = (...paths) => path.resolve(__dirname, ...paths);

const entry = glob.sync('/**/*.@(pug|png|svg)',
    {
        root: resolve('src'),
        nomount: true,
        nosort: true
    })
    .map(x => x.replace(/^\/+/, './'));

module.exports = {
    entry: entry,
    context: resolve('src'),
    output: {
        path: resolve('dist'),
        filename: 'bundle.js',
        publicPath: '/'
    },
    resolve: {
        extensions: [
            '.pug',
            '.ts'
        ],
        mainFiles: [
            'index.pug',
            'index.ts'
        ],
        alias: {
            '@': 'src/'
        },
        modules: [
            resolve('node_modules')
        ]
    },
...

Resulting "HTML" file:

var req = require("!!/home/path-to-project/node_modules/pug-loader/index.js??ref--5-4!/home/path-to-project/src/index.pug");
module.exports = (req['default'] || req).apply(req, .....
zxdong262 commented 6 years ago

this one works

const pugOpts = {
  loader: 'pug-html-loader',
  options: {
    data: {
      version,
      _global: {}
    }
  }
}

      {
        test: /\.pug$/,
        use: [
          'file-loader?name=index.html',
          {
            loader: 'extract-loader',
            options: {
              publicPath: ''
            }
          },
          'html-loader',
          pugOpts
        ]
      }
battlesnake commented 6 years ago

I found that my problem wasn't due to configuration, it was a bug regarding circular dependencies which I've logged separately with an example #39 . I found that after switching from pug-loader+extract-loader to pug-html-loader.