GithubHelp home page GithubHelp logo

colbyfayock / html-webpack-partials-plugin Goto Github PK

View Code? Open in Web Editor NEW
68.0 3.0 20.0 846 KB

πŸ›  Easy HTML partials for Webpack without a custom index!

License: MIT License

JavaScript 100.00%
html-webpack-plugin webpack partials hacktoberfest

html-webpack-partials-plugin's Introduction

Partials for HTML Webpack Plugin

All Contributors

⚠️ This project is no longer actively maintained

Extends HTML Webpack Plugin to add support for partials or templates.

Requirements

Relies on html-webpack-plugin 4+ (currently at beta)

Installation

yarn add html-webpack-partials-plugin -D

or

npm add html-webpack-partials-plugin --save-dev

Usage

Require the plugin in your webpack config:

const HtmlWebpackPartialsPlugin = require('html-webpack-partials-plugin');

Add the plugin to your webpack config as follows:

plugins: [
  new HtmlWebpackPlugin(),
  new HtmlWebpackPartialsPlugin({
    path: './path/to/partials/body.html'
  })
]

Set up your partial:

<div>Hello World!</div>

Settings

Name Type Default Description
path String none Partial location
inject Boolean true Conditionally inject your partial
location String "body" HTML tag name where the the partial gets added
priority String "low" "high", "low", "replace" - high/low determines if the partial gets added from the start of the location or end, while replace replaces the element completely.
template_filename String/String[] "index.html" The filename of the HTML Webpack Plugin template that the partial should be attributed to. By default this is index.html, the HTML Webpack Plugin default output. Additionally, passing * will apply the partial to all templates in the compilation. This doesn't currently work in a regex format, thus something like *.html will NOT work and the only functionality * will provide is to match all templates. You can also pass an array of strings.
options Object {} Local variables/options to the given partial

The settings can either be passed in as a single object or an array of objects.

Examples

React App Root

Don't bother creating a custom template just to add a React root element, simply add it as a partial!

Set Up Your Config

Using an example of webpack.config.js with Babel installed:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPartialsPlugin = require('../../');

module.exports = {
  entry: {
    main: path.join(__dirname, './main.js')
  },
  output: {
    path: path.join(__dirname, './dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react'
            ]
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new HtmlWebpackPartialsPlugin({
      path: path.join(__dirname, './partials/body.html')
    })
  ]
};

Set Up your Partial

Add a mounting point for your application at partials/body.html:

<div id="root"></div>

Results

πŸ’ͺNow your app has something to render to!

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
  <div id="root"></div><script type="text/javascript" src="main.js"></script></body>
</html>

Google Analytics & Google Optimize

The recommended installation of Google Optimize alongside Google Analytics includes installing the snippet immediately after the <meta charset tag from the initial server-returned HTML. Loading this clientside using something like React Helmet, unless using server side rendering, won't give us the benefits of giving an optimal loading experience when running A/B tests. To fix this, we can inject this snippet using a partial without having to create a custom HTML template file or trying to sloppily manage it in our app.

Set Up Your Config

Using a basic example of webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPartialsPlugin = require('../../');

module.exports = {
  entry: {
    main: path.join(__dirname, './main.js') // Not shown in thix example
  },
  output: {
    path: path.join(__dirname, './dist'),
    filename: '[name].js'
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new HtmlWebpackPartialsPlugin([
      {
        path: path.join(__dirname, './partials/analytics.html'),
        priority: 'high',
        location: 'head'
      }
    ])
  ]
};

Set Up your Partial

Using example code from the installation guide, set up partials/analytics.html:

<!-- Page-hiding snippet (recommended)  -->
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'GTM-XXXXXX':true});</script>

<!-- Modified Analytics tracking code with Optimize plugin -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('require', 'GTM-XXXXXX');
ga('send', 'pageview');
</script>

Results

πŸ™† now you're analytics code can be easily maintained and installed in the right spot!

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"><!-- Page-hiding snippet (recommended)  -->
<style>.async-hide { opacity: 0 !important} </style>
<script>(function(a,s,y,n,c,h,i,d,e){s.className+=' '+y;h.start=1*new Date;
h.end=i=function(){s.className=s.className.replace(RegExp(' ?'+y),'')};
(a[n]=a[n]||[]).hide=h;setTimeout(function(){i();h.end=null},c);h.timeout=c;
})(window,document.documentElement,'async-hide','dataLayer',4000,
{'GTM-XXXXXX':true});</script>

<!-- Modified Analytics tracking code with Optimize plugin -->
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('require', 'GTM-XXXXXX');
ga('send', 'pageview');
</script>
    <title>Webpack App</title>
  </head>
  <body>
  <script type="text/javascript" src="main.js"></script></body>
</html>

Other Examples

See a few other working examples here: https://html-webpack-partials-plugin.netlify.app/

See the source for the examples here: https://github.com/colbyfayock/html-webpack-partials-plugin/tree/master/examples

Notes

Determining Injection Point

Given the location and priority passed into the configuration, the plugin determines where to inject. The location is simply the name of the tag to use, where the priority is how high or how low in the tag we inject. For almost all situations, a high priority will inject immediately after the opening tag and low will inject immediately before the closing tag.

The one exception to this, if the passed in tagname is head with a high priority, the plugin will inject immediately after <meta charset="utf-8">.

Order of Injection

The order is determined simply by the order in which the partial is included in the configuration.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Colby Fayock

πŸ’» πŸ“–

Steven Smith

πŸ“–

Aviv Shafir

πŸ’»

Jim Doyle

πŸ’» ⚠️

Septs

πŸ’»

JuFeng Zhang

πŸ’»

Victor Vincent Taglia

πŸ’» πŸ“–

Dae-ho Kim

πŸ’»

This project follows the all-contributors specification. Contributions of any kind welcome!

html-webpack-partials-plugin's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

html-webpack-partials-plugin's Issues

Pass attr/variable to the partial in HTML

Hi, first of all good job with developing the plugin!
I'm wondering whether it's possible to pass a value into the partial from the HTML code like:

<thisIsAPartial variable="value">

so I could then use this value somewhere in the partial

<%= variable %> //of course it doesn't work - I should set this variable in options part of Webpack plugin settings

Cheers!

Partials break when you add data-attributes

I love using this piece of software. It saves me loads of time. Amazing work!
I recently noticed this curious little behaviour recently. I was using the same navbar partial across multiple pages. But in one of the many pages, I had to add a data-attribute to the body tag like this:

<body data-spy="scroll">

And this broke the partial. The navbar shows up just fine on every other page which does not have data attributes. Here's how I was inserting the navbar partial:

new HtmlWebpackPartialsPlugin({ path: path.join(__dirname, "./src/partials/navbar/navbar.html"), location: "body", priority: "high", template_filename: [ "fileWithDataAttributeInBodyTag.html", // 1 "fileWithoutDataAttributeInBodyTag.html", // 2 ] })

The partial works just fine on the second file but doesn't even get inserted in the DOM for the first file.

Add more targetfile options

Hi,

I think it would be good to be able to specify the name of the output file from HTML plugin instead of the name of the template. This is useful when using the same template but injecting different chunks.

 entry: {
    index: './src/',
    other: './src/other',
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Home',
      template: './src/baseof.html',
      filename: 'index.html',
      chunks: ['index'],
    }),
    new HtmlWebpackPlugin({
      title: 'Other',
      template: './src/baseof.html',
      filename: 'other.html',
      chunks: [other'],
    }),
    new HtmlWebpackPartialsPlugin([
      {
        path: path.join(__dirname, './src/index_partial.html'),
        priority: 'high',
        location: 'main',
        // template filename is not useful in this scenario
        template_filename: 'index.html'
      },
      {
        path: path.join(__dirname, './src/other_partial.html'),
        priority: 'high',
        location: 'main',
        // using the name of the output file would be better
        output_filename: 'other.html'
      }
    ]),
  ],

Multiple HtmlWebpackPartialsPlugin()

I am trying to use it to add the main content of a page. The template index.html has the header, navbar and the footer.

[
    new HtmlWebpackPlugin({
      title: "About",
      template: "./src/index.html",
      filename: "about.html" 
    }),
    new HtmlWebpackPartialsPlugin({
      path: "./src/html_templates/about.html",
      location: "main"
    }),
    new HtmlWebpackPlugin({
      title: "Contact",
      template: "./src/index.html",
      filename: "contact.html"
    }),
    new HtmlWebpackPartialsPlugin({
      path: "./src/html_templates/contact.html",
      location: "main"
    })
  ]

As I have it, it simply add the last template path: "./src/html_templates/contact.html" for both about.html and contact.html

meta charset priority not respected in production build

I have an index.html containing:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

and the webpack config uses:

    new HtmlWebpackPartialsPlugin({
      path: './src/analytics.html',
      location: 'head',
      priority: 'high',
      options: {ga_property_id: 'UA-172517233-1'},
    }),

to inject analytics. In the dev server I see the meta tag taking precedence:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"><script async src="...

but the production build the script is pushed before the meta tag: see https://codice.lieve.info/

<!doctype html><html><head><script async src=...</script><meta charset="utf-8">

Plugin version is 0.5.6.

Image path resolving is incorrect

Hi,

First of all thanks for this plugin, really loving it. There is just one issue, and I'm not sure whether it's related to this plugin or not, but let's see.

In my dev environment everything is working fine, and running perfectly. But when I try to compile it, all my paths inside the partials are not getting resolved correctly. They remain the same as they were in my dev environment.

My webpack config looks like this;

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPartialsPlugin = require('html-webpack-partials-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    context: path.resolve('./app'),
    entry: {
        app: './js/index.js'
    },
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: path.resolve(__dirname, './app/views/index.html'),
            inject: true
        }),
        new HtmlWebpackPartialsPlugin({
            path: path.resolve(__dirname, './app/views/partials/sz-main-footer.html'),
            location: "footer",
            template_filename: "index.html",
            options: {
                footerClass: 'sz-pitchdark',
                gradientClass: 'sz-gradient',
                buttonClass: 'dark'
            }
        }),
        new MiniCssExtractPlugin({
            filename: "styles/[name].css",
        }),
    ],
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules\/(?!(dom7|ssr-window|swiper)\/).*/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['minify'],
                        plugins: ["@babel/plugin-proposal-object-rest-spread"]
                    }
                }
            },{
                test: /\.(woff|woff2|eot|ttf)$/,
                loader: "file-loader",
                options: {
                    outputPath: "fonts/",
                    name: "[hash].[ext]",
                }
            }, { 
                test: /\.(html)$/,
                use: {
                    loader: 'html-loader',
                    options: {
                        attrs: ['img:src', ':srcset'],
                        interpolate: require,
                        minimize: true
                    },
                }
              }
        ]
    }
};

------PROD-------

const merge = require('webpack-merge');
const webpack = require('webpack');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = merge(common, {
    mode: 'production',
    devtool: 'source-map',
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new webpack.DefinePlugin({
            'process.ev.NODE_ENV': JSON.stringify('production')
        }),
    ],
    module: {
        rules: [
          {
            test: /\.scss$/,
            use: [{
                loader: MiniCssExtractPlugin.loader,
                options: {
                    publicPath: '../'
                }
            },{
                loader: "css-loader",
            },{
                loader: 'postcss-loader',
                options: {
                    plugins: () => [require('autoprefixer'), require('cssnano')]
                }
            },{
                loader: "sass-loader"
            }]
          },
          {
            test: /\.(gif|png|jpe?g|svg)$/i,
            use: [
                {
                    loader: 'file-loader',
                    options: {
                        name: '[path][name].[ext]'
                    }
                },
                {
                    loader: 'image-webpack-loader',
                    options: {
                      pngquant: {
                        quality: '70-90',
                        speed: 2
                      },
                      optipng: {
                        enabled: false,
                      },
                      mozjpeg: {
                        progressive: true,
                        quality: 70
                      },
                      gifsicle: {
                        enabled: false,
                      }
                    },
                },
            ]
        }
        ]
    }
});

sz-main-footer.html;

<div class="<%= footerClass %>">
    <div class="prefooter">
        <div class="sz-content-wrapper">
            <div class="grid-middle_md-12-center">
                <div class="col-9_md-12">
                    <h2>Let’s brew something together!</h2>
                    <h5>We're ready to be part of your adventure.</h5>
                </div>
                <div class="col-3_md-3_sm-4_xs-7">
                    <a class="sz-primary-button <%= buttonClass %>" href="#">Get in touch</a>
                </div>
            </div>
        </div>
    </div>
    <div class="footer"> 
        <div class="sz-content-wrapper">
            <div class="grid">
                <div class="col-12_md-12">
                    <div class="sz-footer">
                        <ul class="sz-footer-nav">
                            <li>&copy; 2019 Strakzat. All rights reserved.</li>
                            <li><a href="#">Privacy Policy</a></li>
                            <li><a href="#">Terms &amp; Conditions</a></li>
                        </ul>
                        <ul class="sz-footer-social">
                            <li>
                                <a href="#">
                                    <img type="image/svg+xml" src='../../images/general/facebook.svg'></img>
                                </a>
                            </li>
                            <li>
                                <a href="#">
                                    <img type="image/svg+xml" src='../../images/general/instagram.svg'></img>
                                </a>
                            </li>
                            <li>
                                <a href="#">
                                    <img type="image/svg+xml" src='../../images/general/twitter.svg'></img>
                                </a>
                            </li>
                            <li>
                                <a href="#">
                                    <img type="image/svg+xml" src='../../images/general/linkedin.svg'></img>
                                </a>
                            </li>
                        </ul>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="gradient-line <%= gradientClass %> "></div>
</div>

Any ideas how I can fix this? And let my image path inside a partial be correct when compiling? Or is this related to the html-loader? All images inside the HtmlWebpackPlugin page do work tho.

Update readme with template options

Thank you for a great plugin !
I see in the example folder that we can pass in template options. Can you please provide some explanation on its usage in readme

Using CSS selectors for targeting elements

It would be great if we could just specify the CSS selector of the tag we wanna insert the partial in. for example I have a blog signup section that I wanna reuse in multiple pages. But all of those pages have many section tags. My hack for making it work was putting a partial in the aside tag and another partial in the article tag but this way I will quickly run out of tags. If we can develop a way of just targeting DOM elements by their CSS selector(more preferable) or by XPATH, it would highly increase the scope of this plugin.

Question: Multiple partials for one page ?

I have setup my project to use the partials plugin for loading content pages (body-xyz.html).
Now I have one layout.ejs page which requires other html templates, which in whole represent the layout page, means: this layout page is the basis for all pages.

Now I use your plugin for every html-webpack-plugin configuration to dynamically inject the respective body.html.

Unfortunately after upgrading my project to use latest beta version of the html-webpack-plugin ,
I cannot require anymore. see issue.

Now my question:
I would delete all require calls in my layout page and use your plugin to inject the respective partial I need.
I would delete this for example:
` ${require('../../partials/nav.html')} // inside of layout.ejs

Is there a way to configure multiple partials with respective location set for a certain page?

Btw. Appreciate your plugin !

Webpack doesn't recompile in watch mode when a partial template is changed.

In html-webpack-plugin the main.html file will recompile when changed. They fixed this problem in this issue, I think with this commit, by adding the template file to the compilation dependencies.That was in 2015, so idk if there have been api changes or whatnot, but as far as my searching has gone, I think this might be where I'm having trouble right now with both webpack watch and webpack-dev-server not recompiling as I try to edit some partial templates.

Cannot read property 'compilation' of undefined

I ran into problems with this on a project, so I created an extremely stripped down repo try to get to the bottom of it.

The project is using Webpack 4.x with Webpack CLI 3.x

When I run webpack on the project I get the following error:

/usr/local/lib/node_modules/webpack/bin/webpack.js:315
                throw e;
                ^

TypeError: Cannot read property 'compilation' of undefined
    at HtmlWebpackPartialsPlugin.apply (/Users/me/code/webpack-partials-demo/node_modules/html-webpack-partials-plugin/index.js:19:20)
    at Compiler.apply (/usr/local/lib/node_modules/webpack/node_modules/tapable/lib/Tapable.js:306:16)
    at webpack (/usr/local/lib/node_modules/webpack/lib/webpack.js:32:19)
    at processOptions (/usr/local/lib/node_modules/webpack/bin/webpack.js:305:14)
    at Object.<anonymous> (/usr/local/lib/node_modules/webpack/bin/webpack.js:363:1)
    at Module._compile (module.js:652:30)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Live reload

When I use serve from webpack, the live reload does not works when I change a partial file.

`<header>` will be replaced without `<meta charset="utf-8">`

"html-webpack-partials-plugin": "^0.7.0",

Reproduction:

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <header>
        <h1>test</h1>
    </header>
    <header>
        <h1>test</h1>
    </header>
</body>

</html>

analytics.html

<div>HtmlWebpackPartialsPlugin test</div>

webpack config

  plugins: [
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve(__dirname, 'publish/index.html'),
    }),
    new HtmlWebpackPartialsPlugin([
      {
        path: path.resolve(__dirname, 'publish/partials/analytics.html'),
        priority: 'high',
        location: 'head',
      },
    ]),
  ],

result

<!doctype html>
<html lang="en">

<head>
    <div>HtmlWebpackPartialsPlugin test</div>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Document</title>
</head>

<body>

    <head>
        <div>HtmlWebpackPartialsPlugin test</div>
        <h1>test</h1>

        <head>
            <div>HtmlWebpackPartialsPlugin test</div>
            <h1>test</h1>
        </head>
    </head>
</body>

</html>

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.