GithubHelp home page GithubHelp logo

zorigitano / multipage-webpack-plugin Goto Github PK

View Code? Open in Web Editor NEW
170.0 14.0 15.0 267 KB

A plugin that makes handling templates and asset distribution for multi-page applications using webpack trivial

License: Apache License 2.0

JavaScript 100.00%
webpack-plugin webpack multipage webpackplugin webpack2

multipage-webpack-plugin's Introduction

multipage-webpack-plugin

Build Status Coverage Status

webpack plugin that allows for trivial configuration for multi page web applications

Problem

Currently to architect a webpack configuration for multi page web applications, there are many requirements for managing all assets and entry points.

  • In a multipage application every rendered page corresponds to a webpack entry point.

  • Each entry point will have some sort of index.html file or a MVC framework specific server template (partial) which renders to html content.

    • May have different paths, may not even be in the same directory as the entry point.
    • Should contain just the assets bundled for that entry.
    • You would have to create essentially a html-webpack-plugin for each entry however posses extra configuration challenges:

    An example for a Laravel 4 Application using Twig Templates

    const templatesFn = (modules, twigRoot, assetsRoot, shared) => {
      return Object.keys(modules).map((entryName) => {
        return new HtmlWebpackPlugin({
          template: `${assetsRoot}/webpack.template.hbs`, //path.resolve(__dirname, "./assets/webpack.template.hbs"),
          filename: `${twigRoot}/webpack-bundles/${entryName}.twig`,
          chunks: ['inline', 'vendors', entryName, `${shared}`]
        })
      });
    } 
    

Development

  • npm install

Single Test Build

  • npm t

Test Watch

  • npm run test:watch

Usage [WIP]

Plugin Options [WIP]

sharedChunkName vendorChunkName inlineChunkName templateFilename templatePath htmlTemplatePath

multipage-webpack-plugin's People

Contributors

mikebautista avatar pvande avatar suhasdeshpande avatar thelarkinn avatar xiaoiver avatar zorigitano avatar

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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

multipage-webpack-plugin's Issues

Implement long-term vendor caching?

Should I implement this or instead relinquish a bit more control over whether or not recordsPath is set etc. This would have to be modified inside of the plugin before the compiler plugin to any events.

Great POC

Ensure there is a good POC Deisgn on Readme for discussions.

Design and Unit Test Cases

MVP Features

  • Define plugin defaults (no options passed) #5
    • Templates
      • What should we define as the default template output type? (html?)
      • What should the default output path and organization (directory structure) for each template?
    • Emitted Assets #7
      • Should there be any consideration for css chunks? Or should this happen automagically?
      • If css chunks belong to a template, should it be added into a "head" tag? Or should it be manually prescribed to a specific location.
      • Should there be a default vendor chunk? Should it be determined by minChunks: module => module.resource.test(/node_modules/)
      • What is the default vendor chunk name?
      • Should we employ code sharing (CommonsChunkPlugin) across entry points?
      • What is the default shared chunk name?
      • Should these be called '[name].chunk.js'?
      • Which files should be included in each template?
      • Where should emitted assets go? (Respect output property?/Combination)
      • Order of scripts inside template should just work every time regardless of the case
      • Inline bootstrap chunk?
      • chunkhash? md5 webpack plugin? handing hashing on other files?
  • Options to pass
    • specify name of vendor chunk
    • specify name of shared chunk
    • turn shared chunk'ing on or off
    • specify template output extension (one or each)
    • specify template output directory (one or each)
    • specify template output filename (one or each)
    • specify template language? ejs? hbs? etc. (passed through html-webpack-plugin)
    • specify different template for each entry point?
  • Handling Configuration Conflicts
    • Conflicts with CommonsChunkPlugin?
    • Conflicts with html-webpack-plugin?
    • Should error? warning? gracefully inherit behavior?

Optional Features To Investigate

  • http2 integration?
    • AgressiveSplittingPlugin?
      • html-webpack-plugin doesn't currently support this but I believe these split chunks are specified in stats.compilation.entrypoints
    • h/2 Push? Prefetch? Manifest Generation?
  • Service Worker #8
    • offline-plugin / sw-precache-plugin (cc @NekR @addyosmani)
    • What are some possible defaults for server rendered applications in these regards that make sense?
  • separate vendors
    • Legacy apps' entry points may contain outdated or different versions of vendor packages. It would make more sense in that regards that if there are drastic differences in vendors that each entry has a separate vendor.
    • To go super meta there could be benefit (at the cost of an extra network request, but gains in cache-ability), with this feature, a commons vendor could be created for each "entry" as well. This is farfetched however valid.

html-webpack-plugin a required dep for dist package

We need to ensure html-webpack-plugin is a dep not just a dev dep.

→ npm run build

> [email protected] build /Users/req88847/Code/@webpack-examples/vanilla/multipage-example
> webpack --progress --color --verbose

module.js:472
    throw err;
    ^

Error: Cannot find module 'html-webpack-plugin'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/req88847/Code/@webpack-examples/vanilla/multipage-example/node_modules/mul
tipage-webpack-plugin/dist/src/plugin.js:14:25)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)

[WIP] Design - Optional - Service Worker

[WIP] Scenario (Optional) ( #4 )

Fixture

webpack.config.js

const MultipageWebpackPlugin = require(multipage-webpack-plugin);

const config = {
  entry: {
    a: './src/a.js',
    b: './src/b.js'
  },
  output: {
    filename: '[name].chunk.js',
    path: path.join(__dirname, "dist")
  },
  module: {
    /* ... */
  },
  plugins: [
    new MultipageWebpackPlugin()
  ]
};

module.exports = config;

Service Workers

How would service workers be implemented in a "default, out of the box way" for multi page applications (that do not use client routers, or server rendering)?

What existing work can we leverage to help accomplish this behavior (offline-plugin / sw-precache-plugin (cc @NekR @addyosmani))

What are some possible defaults for server rendered applications in these regards that make sense?

Example derived from fixture above:

├── dist/
│   ├── a/ 
│   ├─── index.html
│   ├── b/ 
│   ├─── index.html
│   ├── a.js 
│   ├── b.js
│   ├── shared.js 
│   ├── inline.js
│   ├── vendors.js
│   ├── a.css (if applicable)

** a/index.html **

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script type="text/javascript" src="../../inline.chunk.js"></script>
    <script type="text/javascript" src="../../shared.bundle.js"></script>
    <script type="text/javascript" src="../../vendor.chunk.js"></script>
    <script type="text/javascript" src="../../a.chunk.js"></script>
  </body>
</html>

Design - MVP - Defaults - Emitted Assets

Scenario (Defaults) ( #4 )

Fixture

webpack.config.js

const MultipageWebpackPlugin = require(multipage-webpack-plugin);

const config = {
  entry: {
    a: './src/a.js',
    b: './src/b.js'
  },
  output: {
    filename: '[name].chunk.js',
    path: path.join(__dirname, "dist")
  },
  module: {
    /* ... */
  },
  plugins: [
    new MultipageWebpackPlugin()
  ]
};

module.exports = config;

Emitted Assets

Should there be any consideration for css chunks? Or should this happen automagically?
Per #5 since no arguments are being passed in for template type or extension, then the default output template will be a .html file that is generated from html-webpack-plugin. html-webpack-plugin will automatically emit any init chunk assets (which css [unless lazy loaded] will be included). tl;dr this should happen automagically.

If css chunks belong to a template, should it be added into a "head" tag? Or should it be manually prescribed to a specific location. html-webpack-plugin for its default output template will place css chunks into the <head></head> tag.

Should there be a default vendor chunk? Should it be determined by minChunks: module => module.resource.test(/node_modules/) By default?

  • Users should not have to specify which libraries they are using from their node modules to have separated into a different bundle.
  • Essentially, they should not have to even have the entry point and then vendor chunking automatically happens. (This would be overridden if a vendorChunkName is specified).
  • If there is already an entry point called vendor we should emit a warning saying that if they would not like the default vendor chunking strategy that they specify a "vendorChunkName" option in the options object.

What is the default vendor chunk name?
The most common design pattern is 'vendor'. I think we'll use this one.

Should we employ code sharing (CommonsChunkPlugin) across entry points?
I think by default there is great benefit in sharing code across entry points. The minChunks amount being ~3.

What is the default shared chunk name?
"shared", however if there already exists a chunk name that is called "shared", that we emit a warning from the plugin that says "shared" is creating an automatic shared chunk across entry points and if they would like to use their strategy to specify a "sharedChunkName".

Should these be called '[name].chunk.js'?
Yes, for develop. Production would probably include [chunkhash].chunk.js

Which files should be included in each template?
One single entrypoint will include the following:

  1. the chunk for that entry
  2. vendors chunk
  3. inline chunk which represents the webpack bootstrap
  4. a shared chunk if applicable
  5. css chunks if extract-text-plugin is being used

Where should emitted assets go? (Respect output property?/Combination)
By default the emitted assets (non-template) should respect the existing output.path property and live in the root of that directory.

Order of scripts inside template should just work every time regardless of the case
Yes, html-webpack-plugin should handle this, and to align with the rest of the purpose of this plugin, it shouldn't be a concern of the user.

Example derived from fixture above:

├── dist/
│   ├── a/ 
│   ├─── index.html
│   ├── b/ 
│   ├─── index.html
│   ├── a.js 
│   ├── b.js
│   ├── shared.js 
│   ├── inline.js
│   ├── vendors.js
│   ├── a.css (if applicable)

** a/index.html **

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Webpack App</title>
  </head>
  <body>
    <script type="text/javascript" src="../../inline.chunk.js"></script>
    <script type="text/javascript" src="../../shared.bundle.js"></script>
    <script type="text/javascript" src="../../vendor.chunk.js"></script>
    <script type="text/javascript" src="../../a.chunk.js"></script>
  </body>
</html>

Need to set package main for dist for usage.

We need to set main correctly.

> [email protected] build /Users/req88847/Code/@webpack-examples/vanilla/multipage-example
> webpack --progress --color --verbose

module.js:472
    throw err;
    ^

Error: Cannot find module 'multipage-webpack-plugin'
    at Function.Module._resolveFilename (module.js:470:15)
    at Function.Module._load (module.js:418:25)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/req88847/Code/@webpack-examples/vanilla/multipage-example/webpack.config.j
s:2:32)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)

Design - MVP - Defaults - Templates

Scenario (Defaults) ( #4 )

Fixture

webpack.config.js

const MultipageWebpackPlugin = require(multipage-webpack-plugin);

const config = {
  entry: {
    a: './src/a.js',
    b: './src/b.js'
  },
  output: {
    filename: '[name].chunk.js',
    path: path.join(__dirname, "dist")
  },
  module: {
    /* ... */
  },
  plugins: [
    new MultipageWebpackPlugin()
  ]
};

module.exports = config;

Templates

What should we define as the default template output type?
We use the most simple and compatible template across MVC frameworks and that is .html.

Since under the hood this POC leverages html-webpack-plugin the output/emitted template file makes sense to be .html. By default there would be automatic handling of where script tags should be placed etc.

What should the default output path and organization (directory structure) for each template?
Each template should be emitted into their own subdirectory inside of the specified path found in config.output.path. This sub directory by default would be sane to match the entry name. This way each template can be accessed and served with simple http-server or liteserver or whatever else is out there.

Example derived from fixture above:

├── dist/
│   ├── a/ 
│   ├─── index.html
│   ├── b/ 
│   ├─── index.html

Design - MVP - Inhouse Example

Folder structure will be:

  • A laravel application can be broken up into sections. (Via Composer Packages). These sections live in:
`./packages/mutualofomaha/${packageName}`
  • Each section could have many entry points related to different Server routed views (.twig templates). These JS Entries will be found in:
`./packages/mutualofomaha/${packageName}/src/resources/assets/${entryName}/index.js`
  • The view templates that correspond to these entry points will live in:
`./packages/mutualofomaha/${packageName}/src/resources/views`
  • Each view template will include a twig partial, generated from this plugin, which contains only the scripts to be loaded for that view. These partials are located in:
`./packages/mutualofomaha/${packageName}/src/resources/views/webpack-bundles/${entryName}.bundle.js`

Webpack 4 support

Hi.

I'm following Sean Larkin's Webpack course now on Frontend Masters and he showed us this plugin when I asked a question about how to handle multiple HTML files better than having 30 new HtmlWebpackPlugins,

I was wondering if this plugin will be ported to Webpack 4 or not. I'm willing to help but as of right now I know nothing about how to port plugins to Webpack 4.

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.