Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/node_modules/
/dist/
npm-debug.log
.vscode/
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
This plugin is no longer maintained. Facebook provides a similar plugin:

https://github.com/facebook/create-react-app/blob/edc671eeea6b7d26ac3f1eb2050e50f75cf9ad5d/packages/react-dev-utils/InlineChunkHtmlPlugin.js#L10


Inline Source extension for the HTML Webpack Plugin
========================================
[![npm version](https://badge.fury.io/js/html-webpack-inline-source-plugin.svg)](https://badge.fury.io/js/html-webpack-inline-source-plugin) [![Build status](https://travis-ci.org/DustinJackson/html-webpack-inline-source-plugin.svg?branch=master)](https://travis-ci.org/DustinJackson/html-webpack-inline-source-plugin) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg?style=flat-square)](https://github.com/Flet/semistandard)

Enhances [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin)
functionality by adding the `{inlineSource: 'regex string'}` option.

This is an extension plugin for the [webpack](http://webpack.github.io) plugin [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) (version 4 or higher). It allows you to embed javascript and css source inline.
Warning: This module is a fork from [https://github.com/dustinjackson/html-webpack-inline-source-plugin](https://github.com/dustinjackson/html-webpack-inline-source-plugin) to support Webpack 5.

This is an extension plugin for the [webpack](http://webpack.github.io) plugin [html-webpack-plugin](https://github.com/ampedandwired/html-webpack-plugin) (version 5 or higher). It allows you to embed javascript and css source inline.

Installation
------------
You must be running webpack on node 6 or higher.
You must be running webpack on node 10 or higher.

Install the plugin with npm:
```shell
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import HtmlWebpackPlugin from 'html-webpack-plugin';

export = HtmlWebpackInlineSourcePlugin;
declare class HtmlWebpackInlineSourcePlugin extends Plugin {
constructor(htmlWebpackPlugin: HtmlWebpackPlugin)
constructor(htmlWebpackPlugin?: HtmlWebpackPlugin)
}
declare namespace HtmlWebpackInlineSourcePlugin { }
176 changes: 78 additions & 98 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,139 +1,119 @@
'use strict';
var escapeRegex = require('escape-string-regexp');
var path = require('path');
var slash = require('slash');
var sourceMapUrl = require('source-map-url');

function HtmlWebpackInlineSourcePlugin (htmlWebpackPlugin) {
this.htmlWebpackPlugin = htmlWebpackPlugin;
const assert = require('assert');
const escapeRegex = require('escape-string-regexp');
const path = require('path');
const slash = require('slash');
const sourceMapUrl = require('source-map-url');

let htmlWebpackPlugin = null;
try {
htmlWebpackPlugin = require('html-webpack-plugin');
} catch (_err) {}

function HtmlWebpackInlineSourcePlugin (htmlWebpackPluginOption) {
this.htmlWebpackPlugin = htmlWebpackPluginOption || htmlWebpackPlugin;
assert(!!this.htmlWebpackPlugin, 'html-webpack-inline-source-plugin requires html-webpack-plugin as a peer dependency. Please install html-webpack-plugin');
}

HtmlWebpackInlineSourcePlugin.prototype.apply = function (compiler) {
var self = this;
const self = this;

// Hook into the html-webpack-plugin processing
compiler.hooks.compilation.tap('html-webpack-inline-source-plugin', compilation => {
self.htmlWebpackPlugin
.getHooks(compilation)
.alterAssetTagGroups.tapAsync('html-webpack-inline-source-plugin', (htmlPluginData, callback) => {
if (!htmlPluginData.plugin.options.inlineSource) {
return callback(null, htmlPluginData);
}

var regexStr = htmlPluginData.plugin.options.inlineSource;

var result = self.processTags(compilation, regexStr, htmlPluginData);

callback(null, result);
});
compiler.hooks.compilation.tap('html-webpack-inline-source-plugin', function (compilation) {
const hooks = self.htmlWebpackPlugin.getHooks(compilation);

hooks.alterAssetTags.tap('html-webpack-inline-source-plugin', function (htmlPluginData) {
if (!htmlPluginData.plugin.options.inlineSource) return htmlPluginData;
const regexStr = htmlPluginData.plugin.options.inlineSource;
return self.processTags(compilation, regexStr, htmlPluginData);
});
});
};

HtmlWebpackInlineSourcePlugin.prototype.processTags = function (compilation, regexStr, pluginData) {
var self = this;

var bodyTags = [];
var headTags = [];
const self = this;
const regex = new RegExp(regexStr);
const filename = pluginData.plugin.options.filename;

var regex = new RegExp(regexStr);
var filename = pluginData.plugin.options.filename;
const meta = pluginData.assetTags.meta.map(function (tag) { return self.processTag(compilation, regex, tag, filename); });
const scripts = pluginData.assetTags.scripts.map(function (tag) { return self.processTag(compilation, regex, tag, filename); });
const styles = pluginData.assetTags.styles.map(function (tag) { return self.processTag(compilation, regex, tag, filename); });

pluginData.headTags.forEach(function (tag) {
headTags.push(self.processTag(compilation, regex, tag, filename));
});

pluginData.bodyTags.forEach(function (tag) {
bodyTags.push(self.processTag(compilation, regex, tag, filename));
});

return { headTags: headTags, bodyTags: bodyTags, plugin: pluginData.plugin, outputName: pluginData.outputName };
const result = { ...pluginData };
result.assetTags = { meta, scripts, styles };
return result;
};

HtmlWebpackInlineSourcePlugin.prototype.resolveSourceMaps = function (compilation, assetName, asset) {
var source = asset.source();
var out = compilation.outputOptions;
let source = asset.source();
const out = compilation.outputOptions;
// Get asset file absolute path
var assetPath = path.join(out.path, assetName);
const assetPath = path.join(out.path, assetName);
// Extract original sourcemap URL from source string
if (typeof source !== 'string') {
source = source.toString();
}
var mapUrlOriginal = sourceMapUrl.getFrom(source);
if (typeof source !== 'string') source = source.toString();

const mapUrlOriginal = sourceMapUrl.getFrom(source);
// Return unmodified source if map is unspecified, URL-encoded, or already relative to site root
if (!mapUrlOriginal || mapUrlOriginal.indexOf('data:') === 0 || mapUrlOriginal.indexOf('/') === 0) {
return source;
}
// Figure out sourcemap file path *relative to the asset file path*
var assetDir = path.dirname(assetPath);
var mapPath = path.join(assetDir, mapUrlOriginal);
var mapPathRelative = path.relative(out.path, mapPath);
const assetDir = path.dirname(assetPath);
const mapPath = path.join(assetDir, mapUrlOriginal);
const mapPathRelative = path.relative(out.path, mapPath);
// Starting with Node 6, `path` module throws on `undefined`
var publicPath = out.publicPath || '';
let publicPath = out.publicPath || '';
if (publicPath === 'auto') publicPath = '';

// Prepend Webpack public URL path to source map relative path
// Calling `slash` converts Windows backslashes to forward slashes
var mapUrlCorrected = slash(path.join(publicPath, mapPathRelative));
const mapUrlCorrected = slash(path.join(publicPath, mapPathRelative));
// Regex: exact original sourcemap URL, possibly '*/' (for CSS), then EOF, ignoring whitespace
var regex = new RegExp(escapeRegex(mapUrlOriginal) + '(\\s*(?:\\*/)?\\s*$)');
const regex = new RegExp(escapeRegex(mapUrlOriginal) + '(\\s*(?:\\*/)?\\s*$)');
// Replace sourcemap URL and (if necessary) preserve closing '*/' and whitespace
return source.replace(regex, function (match, group) {
return mapUrlCorrected + group;
});
};

HtmlWebpackInlineSourcePlugin.prototype.processTag = function (compilation, regex, tag, filename) {
var assetUrl;
var preTag = tag;
let assetUrl;

// inline js
if (tag.tagName === 'script' && tag.attributes && regex.test(tag.attributes.src)) {
assetUrl = tag.attributes.src;
tag = {
tagName: 'script',
closeTag: true,
attributes: {
type: 'text/javascript'
}
};

if (tag.tagName === 'script' && regex.test(tag.attributes.src)) assetUrl = tag.attributes.src;
// inline css
} else if (tag.tagName === 'link' && regex.test(tag.attributes.href)) {
assetUrl = tag.attributes.href;
tag = {
tagName: 'style',
closeTag: true,
attributes: {
type: 'text/css'
}
};
}

if (assetUrl) {
// Strip public URL prefix from asset URL to get Webpack asset name
var publicUrlPrefix = compilation.outputOptions.publicPath || '';
// if filename is in subfolder, assetUrl should be prepended folder path
if (path.basename(filename) !== filename) {
assetUrl = path.dirname(filename) + '/' + assetUrl;
}
var assetName = path.posix.relative(publicUrlPrefix, assetUrl);
var asset = getAssetByName(compilation.assets, assetName);
if (compilation.assets[assetName] !== undefined) {
var updatedSource = this.resolveSourceMaps(compilation, assetName, asset);
tag.innerHTML = (tag.tagName === 'script') ? updatedSource.replace(/(<)(\/script>)/g, '\\x3C$2') : updatedSource;
}else{
return preTag;
}
}

return tag;
else if (tag.tagName === 'link' && regex.test(tag.attributes.href)) assetUrl = tag.attributes.href;
// not inline
else return tag;

// Strip public URL prefix from asset URL to get Webpack asset name
let publicPath = compilation.outputOptions.publicPath || '';
if (publicPath === 'auto') publicPath = '';
else if (publicPath && !publicPath.endsWith('/')) publicPath += '/';

// if filename is in subfolder, assetUrl should be prepended folder path
if (path.basename(filename) !== filename) assetUrl = path.dirname(filename) + '/' + assetUrl;

const assetName = path.posix.relative(publicPath, assetUrl);
let asset = compilation.assets[assetName];
if (!asset) asset = getAssetByName(compilation.assets, assetName, publicPath);
if (!asset) return tag; // TODO: handle not found
const updatedSource = this.resolveSourceMaps(compilation, assetName, asset);

return {
tagName: tag.tagName === 'script' ? 'script' : 'style',
closeTag: true,
attributes: { type: tag.tagName === 'script' ? 'text/javascript' : 'text/css' },
innerHTML: tag.tagName === 'script' ? updatedSource.replace(/(<)(\/script>)/g, '\\x3C$2') : updatedSource,
meta: { plugin: 'html-webpack-inline-source-plugin' }
};
};

function getAssetByName (assests, assetName) {
for (var key in assests) {
if (assests.hasOwnProperty(key)) {
var processedKey = path.posix.relative('', key);
if (processedKey === assetName) {
return assests[key];
}
function getAssetByName (assests, assetName, publicPath) {
for (const key in assests) {
if (Object.prototype.hasOwnProperty.call(assests, key)) {
const processedKey = path.posix.relative(publicPath, key);
if (processedKey === assetName) return assests[key];
}
}
}
Expand Down
Loading