Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add transform function #122

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 24 additions & 4 deletions README.md
Expand Up @@ -101,14 +101,34 @@ Note that this will still be executed for each entry in your `paths` array in yo
// The path currently being rendered:
locals.path;

// An object containing all assets:
locals.assets;

// Advanced: Webpack's stats object:
locals.webpackStats;
```

Any additional locals provided in your config are also available.
## Custom locals

To customise the locals provided to your render function you can use the `locals` option.
A function passed to this option will be called before each render.
The result will be used when rendering.

```js
const template = ejs.compile(templateSource);

module.exports = {

...

plugins: [
new StaticSiteGeneratorPlugin({
locals: ({ path, webpackStats }) => {
template,
path,
webpackStats
}
})
]
}
```

## Crawl mode

Expand Down
73 changes: 56 additions & 17 deletions index.js
Expand Up @@ -5,25 +5,29 @@ var cheerio = require('cheerio');
var url = require('url');
var Promise = require('bluebird');

function defaultLocalsTransform(locals) {
return locals;
}

function StaticSiteGeneratorWebpackPlugin(options) {
if (arguments.length > 1) {
options = legacyArgsToOptions.apply(null, arguments);
}

options = options || {};
options = normalizeOptions(options);

this.entry = options.entry;
this.paths = Array.isArray(options.paths) ? options.paths : [options.paths || '/'];
this.locals = options.locals;
this.locals = options.locals || defaultLocalsTransform;
this.globals = options.globals;
this.crawl = Boolean(options.crawl);
}

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

compiler.plugin('this-compilation', function(compilation) {
compilation.plugin('optimize-assets', function(_, done) {
addThisCompilationHandler(compiler, function(compilation) {
addOptimizeAssetsHandler(compilation, function(_, done) {
var renderPromises;

var webpackStats = compilation.getStats();
Expand Down Expand Up @@ -59,19 +63,13 @@ StaticSiteGeneratorWebpackPlugin.prototype.apply = function(compiler) {
});
};

function renderPaths(crawl, userLocals, paths, render, assets, webpackStats, compilation) {
function renderPaths(crawl, transformLocals, paths, render, assets, webpackStats, compilation) {
var renderPromises = paths.map(function(outputPath) {
var locals = {
var locals = transformLocals({
path: outputPath,
assets: assets,
webpackStats: webpackStats
};

for (var prop in userLocals) {
if (userLocals.hasOwnProperty(prop)) {
locals[prop] = userLocals[prop];
}
}
});

var renderPromise = render.length < 2 ?
Promise.resolve(render(locals)) :
Expand All @@ -97,7 +95,7 @@ function renderPaths(crawl, userLocals, paths, render, assets, webpackStats, com
path: key
});

return renderPaths(crawl, userLocals, relativePaths, render, assets, webpackStats, compilation);
return renderPaths(crawl, transformLocals, relativePaths, render, assets, webpackStats, compilation);
}
});

Expand Down Expand Up @@ -132,7 +130,9 @@ var findAsset = function(src, compilation, webpackStatsJson) {
// Webpack outputs an array for each chunk when using sourcemaps
if (chunkValue instanceof Array) {
// Is the main bundle always the first element?
chunkValue = chunkValue[0];
chunkValue = chunkValue.find(function(filename) {
return /\.js$/.test(filename);
});
}
return compilation.assets[chunkValue];
};
Expand All @@ -145,8 +145,10 @@ var getAssetsFromCompilation = function(compilation, webpackStatsJson) {

// Webpack outputs an array for each chunk when using sourcemaps
if (chunkValue instanceof Array) {
// Is the main bundle always the first element?
chunkValue = chunkValue[0];
// Is the main bundle always the first JS element?
chunkValue = chunkValue.find(function(filename) {
return /\.js$/.test(filename);
});
}

if (compilation.options.output.publicPath) {
Expand Down Expand Up @@ -215,6 +217,25 @@ function relativePathsFromHtml(options) {
});
}

function normalizeOptions(legacyOptions) {
var options = Object.assign({}, legacyOptions);

if (options.locals && typeof options.locals !== 'function') {
var userLocals = options.locals;
options.locals = (defaultLocals) => {
return Object.assign(
{
webpackStats: defaultLocals.webpackStats,
path: defaultLocals.path,
assets: defaultLocals.assets
},
userLocals
);
};
}
return options;
}

function legacyArgsToOptions(entry, paths, locals, globals) {
return {
entry: entry,
Expand All @@ -224,4 +245,22 @@ function legacyArgsToOptions(entry, paths, locals, globals) {
};
}

function addThisCompilationHandler(compiler, callback) {
if(compiler.hooks) {
/* istanbul ignore next */
compiler.hooks.thisCompilation.tap('static-site-generator-webpack-plugin', callback);
} else {
compiler.plugin('this-compilation', callback);
}
}

function addOptimizeAssetsHandler(compilation, callback) {
if(compilation.hooks) {
/* istanbul ignore next */
compilation.hooks.optimizeAssets.tapAsync('static-site-generator-webpack-plugin',callback);
} else {
compilation.plugin('optimize-assets', callback);
}
}

module.exports = StaticSiteGeneratorWebpackPlugin;
8 changes: 8 additions & 0 deletions test/__snapshots__/index.spec.js.snap
Expand Up @@ -436,3 +436,11 @@ Object {
"index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
}
`;

exports[`Success cases transform-locals should generate the expected files 1`] = `
Object {
"bar.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
"index.html": "<div>/foo/bar.js<br />/foo/main.js</div>",
"main.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
}
`;
2 changes: 1 addition & 1 deletion test/index.spec.js
Expand Up @@ -6,7 +6,7 @@ const webpack = promisify(require('webpack'));
const rimrafAsync = promisify(require('rimraf'));
const getSubDirsSync = require('./utils/get-sub-dirs-sync');
const dirContentsToObject = require('./utils/dir-contents-to-object');
const directoryContains = require('./utils/directory-contains');
const directoryContains = require('./utils/directory-contains-html');

const successCases = getSubDirsSync(__dirname + '/success-cases');
const errorCases = getSubDirsSync(__dirname + '/error-cases');
Expand Down
1 change: 1 addition & 0 deletions test/success-cases/transform-locals/bar.js
@@ -0,0 +1 @@
module.exports = 'Foo';
3 changes: 3 additions & 0 deletions test/success-cases/transform-locals/index.js
@@ -0,0 +1,3 @@
module.exports = function(locals) {
return '<div>' + locals.chunks.join('<br />') + '</div>';
};
30 changes: 30 additions & 0 deletions test/success-cases/transform-locals/webpack.config.js
@@ -0,0 +1,30 @@
var StaticSiteGeneratorPlugin = require('../../../');
var ejs = require('ejs');
var fs = require('fs');

var paths = ['/', '/foo', '/foo/bar'];

module.exports = {
entry: {
bar: __dirname + '/bar.js',
main: __dirname + '/index.js'
},

output: {
filename: '[name].js',
path: __dirname + '/actual-output',
publicPath: '/foo/',
libraryTarget: 'umd'
},

plugins: [
new StaticSiteGeneratorPlugin({
entry: 'main',
locals: ({ path, webpackStats }) => ({
chunks: Object.keys(webpackStats.compilation.assets).map(
file => `${webpackStats.compilation.outputOptions.publicPath}${file}`
)
})
})
]
};
Expand Up @@ -21,7 +21,7 @@ module.exports = function(referenceDir, targetDir, done) {
});
};

glob('**/*', { cwd: referenceDir, nodir: true }, function(err, files) {
glob('**/*.html', { cwd: referenceDir, nodir: true }, function(err, files) {
if (err) {
return done(err);
}
Expand Down