Giter Club home page Giter Club logo

preload-webpack-plugin's Introduction

preload-webpack-plugin

DEPRECATED: A fork of this project, https://github.com/vuejs/preload-webpack-plugin can be used instead.

A webpack plugin for automatically wiring up asynchronous (and other types) of JavaScript chunks using <link rel='preload'>. This helps with lazy-loading.

Note: This is an extension plugin for html-webpack-plugin - a plugin that simplifies the creation of HTML files to serve your webpack bundles.

Introduction

Preload is a web standard aimed at improving performance and granular loading of resources. It is a declarative fetch that can tell a browser to start fetching a source because a developer knows the resource will be needed soon. Preload: What is it good for? is a recommended read if you haven't used the feature before.

In simple web apps, it's straight-forward to specify static paths to scripts you would like to preload - especially if their names or locations are unlikely to change. In more complex apps, JavaScript can be split into "chunks" (that represent routes or components) at with dynamic names. These names can include hashes, numbers and other properties that can change with each build.

For example, chunk.31132ae6680e598f8879.js.

To make it easier to wire up async chunks for lazy-loading, this plugin offers a drop-in way to wire them up using <link rel='preload'>.

Prerequisites

This module requires webpack v4 and above. It also requires that you're using html-webpack-plugin in your webpack project.

Installation

First, install the package as a dependency in your package.json:

$ npm install --save-dev preload-webpack-plugin

Usage

In your webpack config, require() the preload plugin as follows:

const PreloadWebpackPlugin = require('preload-webpack-plugin');

and finally, add the plugin to your webpack configuration's plugins array after HtmlWebpackPlugin:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin()
]

When preloading files, the plugin will use different as attribute depends on the type of each file. For each file ends with .css, the plugin will preload it with as=style, for each file ends with .woff2, the plugin will preload it with as=font, while for all other files, as=script will be used.

If you do not prefer to determine as attribute depends on suffix of filename, you can also explicitly name it using as:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    as: 'script'
  })
]

In case you need more fine-grained control of the as attribute, you could also provide a function here. When using it, entry name will be provided as the parameter, and function itself should return a string for as attribute:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    as(entry) {
      if (/\.css$/.test(entry)) return 'style';
      if (/\.woff$/.test(entry)) return 'font';
      if (/\.png$/.test(entry)) return 'image';
      return 'script';
    }
  })
]

Notice that if as=font is used in preload, the crossorigin will also be added. Explains can be found in this article, and a list of common as values can be found on MDN.

By default, the plugin will assume async script chunks will be preloaded. This is the equivalent of:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: 'asyncChunks'
  })
]

For a project generating two async scripts with dynamically generated names, such as chunk.31132ae6680e598f8879.js and chunk.d15e7fdfc91b34bb78c4.js, the following preloads will be injected into the document <head>:

<link rel="preload" as="script" href="chunk.31132ae6680e598f8879.js">
<link rel="preload" as="script" href="chunk.d15e7fdfc91b34bb78c4.js">

You can also configure the plugin to preload all chunks (vendor, async, and normal chunks) using include: 'allChunks', or only preload initial chunks with include: 'initial'.

It is very common in webpack to use loaders such as file-loader to generate assets for specific types, such as fonts or images. If you wish to preload these files as well, even if they don't belong to a chunk, you can use include: 'allAssets'.

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: 'allChunks' // or 'initial', or 'allAssets'
  })
]

In case you work with named chunks, you can explicitly specify which ones to include by passing an array:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    include: ['home']
  })
]

will inject just this:

<link rel="preload" as="script" href="home.31132ae6680e598f8879.js">

Filtering chunks

There may be chunks that you don't want to have preloaded (sourcemaps, for example). Before preloading each chunk, this plugin checks that the file does not match any regex in the fileBlacklist option. The default value of this blacklist is [/\.map/], meaning no sourcemaps will be preloaded. You can easily override this:

new PreloadWebpackPlugin({
  fileBlacklist: [/\.whatever/]
})

Passing your own array will override the default, so if you want to continue filtering sourcemaps along with your own custom settings, you'll need to include the regex for sourcemaps:

new PreloadWebpackPlugin({
  fileBlacklist: [/\.map/, /\.whatever/]
})

Filtering HTML

You may not want to preload resources in some of your HTML files. You can use excludeHtmlNames to tell this plugin to ignore one or more files.

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/index.html',
    chunks: ['main']
  }),
  new HtmlWebpackPlugin({
    filename: 'example.html',
    template: 'src/example.html',
    chunks: ['exampleEntry']
  }),
  // Only apply the plugin to index.html, not example.html.
  new PreloadWebpackPlugin({
    excludeHtmlNames: ['example.html'],
  })

Resource hints

Should you wish to use Resource Hints (such as prefetch) instead of preload, this plugin also supports wiring those up.

Prefetch:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'prefetch'
  })
]

For the async chunks mentioned earlier, the plugin would update your HTML to the following:

<link rel="prefetch" href="chunk.31132ae6680e598f8879.js">
<link rel="prefetch" href="chunk.d15e7fdfc91b34bb78c4.js">

Including media

<link> elements have the ability to accept media attributes. These can accept media types or full-blown media queries, allowing you to do responsive preloading.

You can pass the value for the media attribute in the media option:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    media: '(min-width: 600px)'
  })
]

Support

If you've found an error or run into problems, please file an issue.

Patches are encouraged, and may be submitted by forking this project and submitting a pull request through GitHub.

Contributing workflow

src/index.js and src/lib/ contains the primary source for the plugin. test/ contains tests.

Test the plugin:

$ npm install
$ npm run test

The project is written in ES2015, and is transpiled to support node 6 and above.

Additional notes

  • Be careful not to preload resources a user is unlikely to need. This can waste their bandwidth.
  • Use preload for the current session if you think a user is likely to visit the next page. There is no 100% guarantee preloaded items will end up in the HTTP Cache and read locally beyond this session.
  • If optimizing for future sessions, use prefetch and preconnect. Prefetched resources are maintained in the HTTP Cache for at least 5 minutes (in Chrome) regardless of the resource's cachability.

Alternative tools

License

Copyright 2019 Google, Inc.

Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

preload-webpack-plugin's People

Contributors

addyosmani avatar alechill avatar atinux avatar bekos avatar conorhastings avatar developit avatar hanford avatar jackfranklin avatar jeffposnick avatar kuldeepkeshwar avatar laysent avatar malikshahzad228 avatar pd4d10 avatar ragingwind avatar toxic-johann avatar yyx990803 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

preload-webpack-plugin's Issues

Chrome warning

Hi!

I'm not using html-webpack-plugin but am using the strategy implemented by this plugin to preload my async chunks which are the result of code-splitting per route. The HTML looks like this:

<link rel="preload" href="/client.0.js" as="script"/>
<link rel="preload" href="/client.1.js" as="script"/>

When I load the page, only one of the of the chunks are actually used until the user navigates to the other route. Chrome gives me this warning:

The resource http://localhost:3000/client.1.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.

According to the network tab, when on the client.1.js route, the client.0.js chunk is always being loaded first because of the preloads and this appears to have a detrimental impact on perf (compared to not using preloads). It results in the user downloading all the JavaScript, even if the user will never visit all of the routes (probably doesn't matter on desktop but on mobile it'd be nice not to download the extra bytes and save my mobile data).

image

Is there a better strategy that can be implemented? I imagine such a strategy would involve a lot more manual guessing (specific to each app) and require named chunk imports (webpack/webpack#1949) to manually insert a preload (e.g. when a user has scrolled 90% of the way to the CTA)??


Not sure if this is what #11 was getting at.

Adding 'preconnect'

Can we use this plugin to add a 'preconnect' resource hint ? If yes, can someone share an example

2.1.0 update breaking builds

After 2.1.0 was published, our builds started breaking with the following:

ERROR in   TypeError: Object.values is not a function

  - index.js:80 extractedChunks.filter.chunk
    [app]/[preload-webpack-plugin]/index.js:80:93

Is this a config problem on our end, or an edge case missed in this new version?

EDIT: Sorry, looks like Object.values is only available by default in node v7+. Feel free to close this, but it may be nice to add node v7 as a dependency.

Duplicate outputs when using with multiple instances of HtmlWebpackPlugin

new HtmlWebpackPlugin({ filename: '../file-1.html' }),
new HtmlWebpackPlugin({ filename: '../file-2.html' }),
new PreloadWebpackPlugin({ rel: 'prefetch', as: 'script' })

produces file-1.html with

<link rel="prefetch" src="chunk.0.js">
<link rel="prefetch" src="chunk.1.js">
</head>

and file-2.html with

<link rel="prefetch" src="chunk.0.js">
<link rel="prefetch" src="chunk.1.js">
<link rel="prefetch" src="chunk.0.js">
<link rel="prefetch" src="chunk.1.js">
</head>

and so on

Support CSS?

Thought: would it be useful to detect and support CSS via as="style"?
Example within an html-webpack-plugin template here.

RangeError: Maximum call stack size exceeded

Last release causes RangeError.

NodeJS v9.2.0
NPM 5.5.1
Windows 10
preload-webpack-plugin 2.1.1
webpack 3.10.0

webpack.config is pretty simple

...
new HtmlWebpackPlugin({
	filename: 'index.html',
	template: '../index.html',
	minify: {
		collapseWhitespace: true
	},
	favicon: path.resolve(APPROOT, 'favicon.ico')
}),
new PreloadWebpackPlugin({
	rel: 'prefetch'
}),
...

Error log is

ERROR in   RangeError: Maximum call stack size exceeded
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:26 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:26:29
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9
2017-12-19T07:42:13.0221845Z            
2017-12-19T07:42:13.0221845Z            - index.js:31 isChunkBelongToHtml
2017-12-19T07:42:13.0221845Z              [client]/[preload-webpack-plugin]/index.js:31:9

With code-splitting

How to make it work with webpack's internal code-splitting functionality?

Multiple html plugins

Hi,
I have the following use case. In a webpack config I'm creating several html files as in this question. I can't find any way in the documentation to treat that case with preload webpack plugin. That is:

plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template: 'src/index.html',
    chunks: ['main']
  }),
  new HtmlWebpackPlugin({
    filename: 'example.html',
    template: 'src/example.html',
    chunks: ['exampleEntry']
  }),
  // I want this to affect only index.html
  new PreloadWebpackPlugin()     
]

Is it possible to do it with this plugin? In the README there are only examples on how to filter the chunks, but not the destination.

Thanks

invalid configuration object

when I try to run the demo I get:

npm run prod

Invalid configuration object. webpack-dev-server has been initialised using a configuration object that does not match the API schema.

  • configuration has an unknown property 'inject'. These properties are valid:
    object { hot?, hotOnly?, lazy?, host?, filename?, publicPath?, port?, socket?, watchOptions?, headers?, clientLogLevel?, key?, cert?, ca?, pfx?, pfxPassphrase?, inline?, public?, https?, contentBase?, watchContentBase?, open?, features?, compress?, proxy?, historyApiFallback?, staticOptions?, setup?, stats?, reporter?, noInfo?, quiet?, serverSideRender?, index?, log?, warn? }

osx, node 6.9.1, npm 4.1.1

Include + Sourcemaps not working correctly

Hi,

when you are building with sourcemaps you end up with an array of files as chunk.files. There is already a PR of someone pending for this issue. The code in the PR seems to create two link elements, one for the sourcemap and one for the javascript files, I thought they were supposed to be excluded by default?

<link rel=prefetch href=/static/js/player-profile.1a053006248a6348da68.js, /static/js/player-profile.1a053006248a6348da68.js.map>

I was able to resolve this issue by only returning the first index of the array instead:

else if (Array.isArray(options.include)) {
          // Keep only user specified chunks
          extractedChunks = compilation
              .chunks
              .filter((chunk) => {
                const chunkName = chunk.name;
                // Works only for named chunks
                if (!chunkName) {
                  return false;
                }
                return options.include.indexOf(chunkName) > -1;
              })
              .map(chunk => chunk.files[0]); // only using the first index (actual path)
        }

now the output is correct again:

<link rel=prefetch href=/static/js/player-profile.1a053006248a6348da68.js>

Is this actually a bug with the code or did I just do something wrong while using the plugin?

ERROR in TypeError: cb is not a function

preload-webpack-plugin": "^3.0.0-alpha.3
webpack": "^4.16.
DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead
ERROR in TypeError: cb is not a function

Preload after timeout

Hi, I've been experimenting with this lib and so far it seems really straight forward. I have one question though. Is it possible to setup a timeout after which the preloading starts?

My usecase is:
Let's say I am on slow 3G, the main app is 1.2 mb. Chunks are additional 2mb.
User navigates to the page, it starts loading, but while it loads crucial parts, it starts preloading the additional chunks slowing down the time of first meaningful pain. It would be ideal if it could wait until there's no network traffic but I assume that wouldn't be so straight forward so maybe a timeout at least?

What do you think?

How to verify that the plugin is actually working?

I am not convinced that my prefetched chunks are actually being used. When I click a link on my page to load new chunks, the network tab shows new requests happening for the chunks even though chunks were prefetched at page load time.

If I load the initial page, then kill my local server, then click on a link to load new chunks, a net::ERR_CONNECTION_REFUSED error will happen. Shouldn't we expect the cached/prefetched chunks to be used instead of network requests being initiated?

I am using the following setting for the plugin:

new PreloadWebpackPlugin({
  rel: 'prefetch',
}),

I am using plugin version 1.2.2 and Chrome 60.0.3112.90.

Inject preload polyfill?

As of today only Chrome supports preload. Would it make sense to provide an option where Webpack can inject a preload polyfill? Either by specifying a chunk or really just inlining in the HTML (which makes more sense I guess).

Happy to try a PR if that sounds reasonable.

No preload links inserted for fonts?

I'm working on a PWA built using preact cli and I would like to have my font files preloaded but having tried fiddling with my config for hours, it never works.

In my SCSS I have some font declarations

@font-face {
	font-family: 'Inter UI';
	font-display: fallback;
	font-style:  normal;
	font-weight: 400;
	src: url("../assets/fonts/Inter-UI-Regular.woff2") format("woff2"),
	url("../assets/fonts/Inter-UI-Regular.woff") format("woff");
}

@font-face {
	font-family: 'Inter UI';
	font-display: fallback;
	font-style:  normal;
	font-weight: 600;
	src: url("../assets/fonts/Inter-UI-SemiBold.woff2") format("woff2"),
	url("../assets/fonts/Inter-UI-SemiBold.woff") format("woff");
}

And I've tried the allAssets and fileWhiteList settings as described in the README, but there is never any preload links inserted in the HTML.

I have seen that this feature was supported in 2.3.0 which is the version I'm using, so I'm confused why it's not working...

tapAsync undefined in webpack4

Building with PreloadWebpackPlugin enabled causes following error:


/home/alex/GIT/proj/node_modules/preload-webpack-plugin/build/index.js:163
          compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync(_this2.constructor.name, function (htmlPluginData, callback) {
                                                                  ^

TypeError: Cannot read property 'tapAsync' of undefined
    at /home/alex/GIT/proj/node_modules/preload-webpack-plugin/build/index.js:163:67

Project package versions:
[email protected]
[email protected]

Impose a minimum supported version of node + transpile against that

As #45 illustrates, it's easy to slip in functionality that breaks compatibility with older versions of node.

We should do two things to address this:

  • Impose a minimum supported node version in the engines field, set to the minimum version of node that is still officially supported by the Node.js foundation. (4.x until April 2018.) This is a breaking change and should be done in 3.x.
  • Use @babel/preset-env to transpile against that version, and publish the transpiled code to npm.

Filtering chunks

It would be nice if preload-webpack-plugin supports filtering chunks (only include some chunks/exclude some chunks.) like html-webpack-plugin's one.

It will be useful on some use-cases.

  1. Some chunks (e.g. Admin page) may contain some sensitive information. so user wants to exclude it from preload targets. (blacklisting)
  2. Some chunks don't need to be preloaded. so user wants to include some chunks only (whitelisting)

Produces invalid content for XHTML

While html-webpack-plugin has a config for generating XHTML code, this plugin, which is often used in conjunction with html-webpack-plugin produces only HTML tags.

If the plugin were to generate self-closing tags, this would work for HTML and XHTML doctypes.

Injecting font files links

Hello,

I tried to have my custom fonts preloaded :

<link rel="preload" href="/static/fonts/FiraGO-Regular.b68.woff2" as="font" type="font/woff" crossorigin="anonymous">

but I wasnt able with several configuration options.

Where should the font files be imported to force the plugin to generate the <link>s?

Is the plugin capable of that? (I read some old Pull Requests hinting this is not possible)

Chrome net error

Using preload plugin causes ERR_INSUFFICIENT_RESOURCES in Chrome Version 56.0.2924.87 (64-bit).
My webpack settings :

  new PreloadWebpackPlugin({
    rel           : 'prefetch',
    include       : 'all',
    fileBlacklist : [/\.js\.map/, /app*.*\.js/, /vendor*.*\.js/]
  })

Whitelisting chunks

It would be useful if preload-webpack-plugin supported an option to filter chunks using a whitelist as a complement to the current fileBlacklist option.

My suggestion would be to allow the include option to contain a Regular Expressions in addition to strings.

I'm happy to submit a PR, if this is something that others would also find useful ๐Ÿ˜Š


Related to #6

ERROR in Error: Chunk.parents: Use ChunkGroup.getParents() instead

Installed the new Version 2.3.0 with webpack 4.1.1, and get this error with chunks:


ERROR in   Error: Chunk.parents: Use ChunkGroup.getParents() instead

  - Chunk.js:438 Chunk.get
    [berater-backend]/[webpack]/lib/Chunk.js:438:9

  - index.js:40 doesChunkBelongToHTML
    [berater-backend]/[preload-webpack-plugin]/index.js:40:30

  - index.js:116 extractedChunks.filter.chunk
    [berater-backend]/[preload-webpack-plugin]/index.js:116:61

  - Array.filter

  - index.js:116 compilation.plugin
    [berater-backend]/[preload-webpack-plugin]/index.js:116:45

  - new Promise

  - Hook.js:35 AsyncSeriesWaterfallHook.lazyCompileHook [as _promise]
    [berater-backend]/[tapable]/lib/Hook.js:35:21

  - index.js:643
    [berater-backend]/[html-webpack-plugin]/index.js:643:47

  - index.js:173 Promise.resolve.then.then.then.then.then.then.html
    [berater-backend]/[html-webpack-plugin]/index.js:173:18

  - next_tick.js:118 process._tickCallback
    internal/process/next_tick.js:118:7

Do you need my webpack.config?

Not respecting `output.publicPath`

Currently the links uses the raw entry filenames, so they are assumed to be loaded from the root (publicPath: '/'). This breaks when we use a different publicPath.

Should be an easy fix at a first glance, will likely submit a PR later when I got time.

Support multiple html-webpack-plugin instances

I wrote most of the html-webpack-plugin code and would ask you to adapt your plugin a little bit.

Instead of string search and replace you might want to alter the assets array:
https://github.com/jantimon/resource-hints-webpack-plugin/blob/master/index.js#L87-L89

Instead of using the options of your plugin you might want to extend the html-webpack-plugin options so it can be used in multiple instances:
https://github.com/jantimon/resource-hints-webpack-plugin/blob/master/index.js#L64

Semantic version is incorrect.

between 1.2.2 and 1.2.3 you switch the peer dependency from webpack 2.x to v3.x. I should say that this is quite breaking change. Now because the package.json was set with ^1.2.2 it installed 1.2.3 thinking it's OK, except it's not. Please consider changing the major version.

Toggle preload/prefetch based on chunk.initial (or a callback)

The current plugin requires that you choose between a single rel: 'preload' or rel: 'prefetch' value that applies to all of the <link>s.

The problem is that rel="preload" is appropriate for subresources that are used immediately, and rel="prefetch" is appropriate for subresources that are lazy-loaded or used on a subsequent navigation. It's possible to have a mix of of those two types of subresources in different webpack chunks.

I'm in favor of changing the way rel works as follows:

  • If a string rel value is specified in the config, then always use that for all <link>s.
  • If no rel value is specified in the config, then use chunk.initial ? 'preload' : 'prefetch' to determine the rel value for each <link>.
  • If a function rel value is specified in the config, then pass in the file path and chunk and use the return value to determine the rel value for each <link>. (This is similar to what as supports, but instead of being passed just the file path, you'd also pass in the chunk.)

CC: @addyosmani

New config option to opt-in to crossorigin="anonymous"

Amazon S3 not send CORS headers if use <link rel="prefetch"> without crossorigin attribute.
This response is cached by Chrome, and reuse next access by script tag.
So this script is blocked by CORS policy.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="initial-scale=1">
  <title>crossorigin test</title>
  <link rel="prefetch" href="https://s3-ap-northeast-1.amazonaws.com/macoshita-test-crossorigin/main.js">
</head>
<body>
  <h1>crossorigin prefetch test (maybe fail)</h1>
  <a id="test" href="javascript:void(0)">Click to load script</a>
  <script>
    document.getElementById('test').addEventListener('click', function () {
      const script = document.createElement('script')
      script.src = 'https://s3-ap-northeast-1.amazonaws.com/macoshita-test-crossorigin/main.js'
      script.crossOrigin = 'crossorigin'

      // will be blocked
      document.getElementsByTagName('head')[0].appendChild(script)
    }, false)
  </script>
</body>
</html>

Webpack 4 support

Webpack 4 (which I hear is shipping in Feb. 2018) will introduce changes to the plugin system, and there might be changes required for this plugin to be compatible.

I don't specifically know what might need to change, but I'm opening this as a placeholder to investigate further, and an opportunity to folks from the community who have been involved in migrating other plugins to contribute.

Chrome Warning message regarding not using preloaded chunks

Just trying out this plugin for two chunks generated by webpack code splitting, everything seems to working fine but in console I am getting these warnings.

The resource http://localhost:8080/98196ebdaabca2c98261.js was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.

Now the error makes sense, but it could take the user a few seconds to navigate to the route which requires these chunks. Is there anyway to stop this error message ?

I.e I preload these code-splitting chunks as follows

<link rel="preload" href="98196ebdaabca2c98261.js" as="script">
<link rel="preload" href="0f4f2b938549bee12ab7.js" as="script">

but they are not loaded on "home" route, only when the user navigates to i.e. "favourites"

Edit : I guess I should be using prefetch

css preload also includes the synchronous link

Hello everyone,
I'm currently working on a react app ejected from create-react-app, and in a quest of getting the shortest loading time (and highest pagespeed insight score I admit), I have decided to load everything asynchronously in index.html, and inline a critical css.
So far I've used ScriptExtHtmlWebpackPlugin to async load the main js file.
After that I still got a warning because of a blockig main css file, and I was happy to find this project.

This is how I got it configured :

new ScriptExtHtmlWebpackPlugin({
    defaultAttribute: 'async'
}),
new PreloadWebpackPlugin({
    rel: 'preload',
    as: 'style',
    include: 'all',
    fileBlacklist: [/\.map|.js/]
}),

I've excluded js files since I only wanted to target the css.

and this is what I got at the end

<link rel="preload" href="/static/css/main.f5b70207.css" as="style">
<link href="/static/css/main.f5b70207.css" rel="stylesheet">

Maybe I've missed something, but how come we get 2 links here? Would it be possible to only get the preload one?

Filter assets by initial chunk

Continuation of #35.

If I have two chunks ("foo" and "bar)" loading one asset using file-loader each ("foo.png" and "bar.png") with an HtmlWebpackPlugin each ("foo.html" and "bar.html"), I want "foo.html" to only preload "foo.png", and "bar.html" to only preload "bar.png".

If I have a third chunk "baz" (using a third HtmlWebpackPlugin "baz.html") which uses file-loader to load both "foo.png" and "bar.png", I want both images to be preloaded in "baz.html".

I assume this could be done by new include option (similar to "allChunks").

Provide a way to include all assets, not only chunks

As discussed briefly in #29, for current version of plugin, only chunks are processed. That means, for most of the cases, only JavaScript files and CSS files (which are exported using extract-text-webpack-plugin) can be added as preload using this plugin. Resources such as image and fonts, which are exported via file-loader, are not chunks but only assets, thus will not be handled by this plugin.

I would suggest to provide an opt-in option to include not only chunks but all assets when running the plugin. For example:

new PreloadWebpackPlugin({
  rel: 'preload',
  include: 'all-assets', // to include both chunks and other assets
  fileBlacklist: [/\.js$/, /\.css$/, /\.woff2$/],
});

Could hurt performance

My hypothesis is that default setup of this plugin could actually hurt performance. It adds the resource with the highest prio on the network queue. Delaying critical resources when bandwidth congestion occurs or the max connections have been taken. Basically takes away the benefit of lazyloading. If the hypothesis is proven, it would be better to add them as prefetch by default and optionally as preload

See: NOTE: relationship to prefetch -> https://www.w3.org/TR/preload/
screen shot 2017-02-03 at 16 57 40

how can I go to Preload my Chunks as needed?

This is a cool plugin, thanks to the author,
But I have a question, how can I go to Preload my Chunks as needed?
I hope to set the Preload property according to the Chunks that the page needs, instead of setting each Chunk, which will waste bandwidth.
Because I can't determine the name of the Chunk needed for each page, I can't use the blacklist/whitelist.

media tag for images [enhancement]

Is it possible to include a media tag for certain preloaded assets. Specifically i want to include a preload link for my banner images. The desired output would be something like this below.

<!--preload image headers-->
<link rel="preload" as="image" href="images/landing-page-banner_mobile.jpg" media="(max-width: 600px)">
<link rel="preload" as="image" href="images/landing-page-banner_s.jpg" media="(max-width: 960px)">
<link rel="preload" as="image" href="images/landing-page-banner_m.jpg" media="(max-width: 1440px)">
<link rel="preload" as="image" href="images/landing-page-banner_l.jpg" media="(min-width: 1441px)">

Proposed change: validate `rel` option against accepted values in spec and supported values in project

Mind if I submit a function to validate the rel option in the plugin constructor? For values allowed by the spec but not supported by the plugin (e.g. preconnect) it would follow the existing pattern of issuing a console.warn to let the user know they've probably made a mistake, but not break the build as they may have a valid reason for doing this (e.g. using the plugin to test an implementation of preconnect). For values not allowed by the spec, it would follow the existing pattern of issuing a log.error and throwing the same message as an error.

This behavior would be wrapped in a function called in the plugin constructor. For instance, index.js line 30 would be: validateRel(this.options.rel);, coming after the default options are applied so as not to make assumptions about how the supplied value interacts with the default, but rather make an assertion on the option ultimately making it into the build.

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.