webdiscus / pug-loader

Pug loader for Webpack renders pug to HTML or template function
https://webdiscus.github.io/pug-loader/pug-filters
ISC License
72 stars 5 forks source link

webpack-dev-server: pages require access with .html #27

Closed mjlbach closed 1 year ago

mjlbach commented 1 year ago

Hi!

Thanks for this package, I'm in the process of migrating from HtmlWebpackPlugin and using pug-loader from an older website.

One issue, is that while in production our website is fine, when using webpack-dev-server all links to our pages (people, research, publications ,etc.) require an .html postfix. I'm wondering if I've done something wrong, or if you have suggestions as to what I can try? Do I need to use the rewrite field?

My understanding is this should be handled by the magicHtml field https://webpack.js.org/configuration/dev-server/

webpack.common.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const PugPlugin = require('pug-plugin');

module.exports = {
  entry: {
    index: './src/app/home/index.pug',
    people: './src/app/people/index.pug',
    research: './src/app/research/index.pug',
    publications: './src/app/publications/index.pug',
    resources: './src/app/resources/index.pug',
    teaching: './src/app/teaching/index.pug',
    apply: './src/app/apply/index.pug'
  },
  output: {
    filename: 'app/[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'auto'
  },
  plugins: [
    new PugPlugin({
      js: {
        // output filename of extracted JS file from source script defined in Pug
        filename: 'assets/js/[name].[contenthash:8].js',
      },
      css: {
        // output filename of extracted CSS file from source style defined in Pug
        filename: 'assets/css/[name].[contenthash:8].css',
      },
    })
  ],
  module: {
    rules: [
      {
        test: /\.(pug)$/,
        loader: PugPlugin.loader
      },
      {
        test: /\.s[ac]ss$/,
        use: [
          // "style-loader",
          "css-loader",
          "sass-loader"
        ]
      },
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(png|jpg|jpeg|ico|svg)/,
        type: 'asset/resource',
        generator: {
          // output filename of images
          filename: 'assets/images/[name].[hash:8][ext]',
        },
      },
      {
        test: /font-awesome\/.+\/.+\.(eot|svg|ttf|otf|woff(2)?)(\?v=\d+\.\d+\.\d+)?$/,
        use: [{
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'fonts/'
          }
        }]
      }
    ]
  }
};

webpack.dev.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map',
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist'),
      serveIndex: true,
    },
  }
});
webdiscus commented 1 year ago

Hello @mjlbach,

Thank You for the reporting of the issue. I try to reproduce it.

P.S. You could greatly speed up the solution of the problem if you created a small repo with a reproducible issue.

webdiscus commented 1 year ago

@mjlbach

I will help you but I can't reproduce an issue.

I have created the example simple multiple pages.

Can you please create a small repo based on this example to reproduce a problem.

Describe please:


Clarification

Entry

The key of the entry object is the output filename (without .html extension) relative to output.path. For details see entry-syntax.

entry: {
    index: './src/app/home/index.pug', // output ./dist/index.html
    people: './src/app/people/index.pug', // output ./dist/people.html

    // output a generated HTML file to sub directory
    'pages/research': './src/app/research/index.pug', // output ./dist/pages/research.html
},

Output

output: {
    filename: 'app/[name].bundle.js', // don't define it here, this is the same as Plugin option `js.filename`
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'auto' // default is always `auto`, can be omited
},

file-loader

Note: the file-loader is deprecated and in Webpack 5 is replaced with asset/resource, see the asset-modules. Use the asset module asset/resource:

     {
        test: /font-awesome\/.+\/.+\.(eot|svg|ttf|otf|woff(2)?)(\?v=\d+\.\d+\.\d+)?$/,
        type: 'asset/resource',
        generator: {
          // output filename of fonts
          filename: 'assets/fonts/[name][ext][query]',
        },
      }
mjlbach commented 1 year ago

Thank you so much for the repro and the proactive suggestions on cleaning up our config! It was a hard migration with the webpack upgrades as well haha.

When I use your repo, I can reproduce the problem:

with npm start

Screenshot 2023-02-22 at 7 44 35 AM Screenshot 2023-02-22 at 7 44 32 AM

with npm run build && cd dist && npx serve

Screenshot 2023-02-22 at 7 45 05 AM Screenshot 2023-02-22 at 7 45 01 AM

Then apply this patch:

diff --git a/examples/simple-multipage/src/views/home/index.pug b/examples/simple-multipage/src/views/home/index.pug
index c9c34ac..fcc7b21 100644
--- a/examples/simple-multipage/src/views/home/index.pug
+++ b/examples/simple-multipage/src/views/home/index.pug
@@ -9,7 +9,7 @@ html
 body
   h1 Home
   div.nav
-    a(href="about.html") About
+    a(href="about") About
     span &nbsp|&nbsp
-    a(href="contact.html") Contact
+    a(href="contact") Contact
   img(src=require('Images/apple.png') alt="apple")

with npm start

image image image

with npm build && cd dist && npx serve

image image
webdiscus commented 1 year ago

@mjlbach

ah, now I understand your problem.

According to the Web Standards Specification:

If you need to have a URL as a web path (without .html), then change in the Webpack entry:

entry: {
    // define URL: https://example.com (real URL: https://example.com/index.html)
    index: 'src/views/home/index.pug', // => dist/index.html

    // define URL: https://example.com/contact.html
    contact: 'src/views/contact/index.pug', // => dist/contact.html

    // define URL: https://example.com/about (real URL: https://example.com/about/index.html)
    'about/index': 'src/views/about/index.pug', // => dist/about/index.html
},
mjlbach commented 1 year ago

Ah I had tried this before and thought it was a hack! Good to hear this is the recommended solution :)

I was confused because when I build/serve the site with cloudflare (and npx serve) it still works without changing the above, and with our previous setup (using html-webpack-plugin) webpack-dev-server it also worked. Do you know what might have changed?

webdiscus commented 1 year ago

@mjlbach

It was a "magic" of a web-server (cloudfare has non-standard configuration to allow more flexibility). Just follow Web Standards to avoid unexpected problems ;-)

mjlbach commented 1 year ago

I see. Thanks so much for all of your help!