├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── index.js
├── jest.config.js
├── package.json
└── test
├── __snapshots__
└── index.spec.js.snap
├── error-cases
├── missing-source
│ ├── expected-error.js
│ ├── index.js
│ └── webpack.config.js
├── non-function-export
│ ├── expected-error.js
│ ├── index.js
│ └── webpack.config.js
└── render-error
│ ├── expected-error.js
│ ├── index.js
│ └── webpack.config.js
├── index.spec.js
├── success-cases
├── basic-promise
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── basic-sync
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── basic
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── compression
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── crawl-ignore
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── crawl-relative-iframes
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── crawl-relative
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── crawl-root-relative-iframes
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── crawl-root-relative
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── custom-file-names
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── default-entry-when-named
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── entry-via-file-name
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── entry-via-name
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── es-modules
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── ignore-inherited-locals
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── legacy-args
│ ├── foo.js
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── multi-render-custom-file-names
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── multi-render
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
├── no-options-provided
│ ├── index.js
│ └── webpack.config.js
├── require-ensure
│ ├── foo.js
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
└── single-path
│ ├── index.js
│ ├── template.ejs
│ └── webpack.config.js
└── utils
├── dir-contents-to-object.js
├── directory-contains.js
└── get-sub-dirs-sync.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | actual-output
3 | coverage
4 | *.log
5 | yarn.lock
6 | package-lock.json
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "6"
4 | after_script:
5 | - npm run coveralls
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Mark Dalgleish
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](http://travis-ci.org/markdalgleish/static-site-generator-webpack-plugin) [](https://coveralls.io/r/markdalgleish/static-site-generator-webpack-plugin) [](https://david-dm.org/markdalgleish/static-site-generator-webpack-plugin) [](https://npmjs.org/package/static-site-generator-webpack-plugin)
2 |
3 | # static site generator webpack plugin
4 |
5 | Minimal, unopinionated static site generator powered by webpack.
6 |
7 | Bring the world of server rendering to your static build process. Either provide an array of paths to be rendered, or *crawl your site automatically*, and a matching set of `index.html` files will be rendered in your output directory by executing your own custom, webpack-compiled render function.
8 |
9 | This plugin works particularly well with universal libraries like [React](https://github.com/facebook/react) and [React Router](https://github.com/rackt/react-router) since it allows you to pre-render your routes at build time, rather than requiring a Node server in production.
10 |
11 | ## Install
12 |
13 | ```bash
14 | $ npm install --save-dev static-site-generator-webpack-plugin
15 | ```
16 |
17 | ## Usage
18 |
19 | Ensure you have webpack installed, e.g. `npm install -g webpack`
20 |
21 | ### webpack.config.js
22 |
23 | ```js
24 | const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
25 |
26 | module.exports = {
27 |
28 | entry: './index.js',
29 |
30 | output: {
31 | filename: 'index.js',
32 | path: 'dist',
33 | /* IMPORTANT!
34 | * You must compile to UMD or CommonJS
35 | * so it can be required in a Node context: */
36 | libraryTarget: 'umd'
37 | },
38 |
39 | plugins: [
40 | new StaticSiteGeneratorPlugin({
41 | paths: [
42 | '/hello/',
43 | '/world/'
44 | ],
45 | locals: {
46 | // Properties here are merged into `locals`
47 | // passed to the exported render function
48 | greet: 'Hello'
49 | }
50 | })
51 | ]
52 |
53 | };
54 | ```
55 |
56 | ### index.js
57 |
58 | Sync rendering:
59 |
60 | ```js
61 | module.exports = function render(locals) {
62 | return '' + locals.greet + ' from ' + locals.path + '';
63 | };
64 | ```
65 |
66 | Async rendering via callbacks:
67 |
68 | ```js
69 | module.exports = function render(locals, callback) {
70 | callback(null, '' + locals.greet + ' from ' + locals.path + '');
71 | };
72 | ```
73 |
74 | Async rendering via promises:
75 |
76 | ```js
77 | module.exports = function render(locals) {
78 | return Promise.resolve('' + locals.greet + ' from ' + locals.path + '');
79 | };
80 | ```
81 |
82 | ## Multi rendering
83 |
84 | If you need to generate multiple files per render, or you need to alter the path, you can return an object instead of a string, where each key is the path, and the value is the file contents:
85 |
86 | ```js
87 | module.exports = function render() {
88 | return {
89 | '/': 'Home',
90 | '/hello': 'Hello',
91 | '/world': 'World'
92 | };
93 | };
94 | ```
95 |
96 | Note that this will still be executed for each entry in your `paths` array in your plugin config.
97 |
98 | ## Default locals
99 |
100 | ```js
101 | // The path currently being rendered:
102 | locals.path;
103 |
104 | // An object containing all assets:
105 | locals.assets;
106 |
107 | // Advanced: Webpack's stats object:
108 | locals.webpackStats;
109 | ```
110 |
111 | Any additional locals provided in your config are also available.
112 |
113 | ## Crawl mode
114 |
115 | Rather than manually providing a list of paths, you can use the `crawl` option to automatically crawl your site. This will follow all relative links and iframes, executing your render function for each:
116 |
117 | ```js
118 | module.exports = {
119 |
120 | ...
121 |
122 | plugins: [
123 | new StaticSiteGeneratorPlugin({
124 | crawl: true
125 | })
126 | ]
127 | };
128 | ```
129 |
130 | Note that this can be used in conjunction with the `paths` option to allow multiple crawler entry points:
131 |
132 | ```js
133 | module.exports = {
134 |
135 | ...
136 |
137 | plugins: [
138 | new StaticSiteGeneratorPlugin({
139 | crawl: true,
140 | paths: [
141 | '/',
142 | '/uncrawlable-page/'
143 | ]
144 | })
145 | ]
146 | };
147 | ```
148 |
149 | ## Custom file names
150 |
151 | By providing paths that end in `.html`, you can generate custom file names other than the default `index.html`. Please note that this may break compatibility with your router, if you're using one.
152 |
153 | ```js
154 | module.exports = {
155 |
156 | ...
157 |
158 | plugins: [
159 | new StaticSiteGeneratorPlugin({
160 | paths: [
161 | '/index.html',
162 | '/news.html',
163 | '/about.html'
164 | ]
165 | })
166 | ]
167 | };
168 | ```
169 |
170 | ## Globals
171 |
172 | If required, you can provide an object that will exist in the global scope when executing your render function. This is particularly useful if certain libraries or tooling you're using assumes a browser environment.
173 |
174 | For example, when using Webpack's `require.ensure`, which assumes that `window` exists:
175 |
176 | ```js
177 | module.exports = {
178 | ...,
179 | plugins: [
180 | new StaticSiteGeneratorPlugin({
181 | globals: {
182 | window: {}
183 | }
184 | })
185 | ]
186 | }
187 | ```
188 |
189 | ## Asset support
190 |
191 | template.ejs
192 | ```ejs
193 | <% css.forEach(function(file){ %>
194 |
195 | <% }); %>
196 |
197 | <% js.forEach(function(file){ %>
198 |
199 | <% }); %>
200 | ```
201 |
202 | index.js
203 | ```js
204 | if (typeof global.document !== 'undefined') {
205 | const rootEl = global.document.getElementById('outlay');
206 | React.render(
207 | ,
208 | rootEl,
209 | );
210 | }
211 |
212 | export default (data) => {
213 | const assets = Object.keys(data.webpackStats.compilation.assets);
214 | const css = assets.filter(value => value.match(/\.css$/));
215 | const js = assets.filter(value => value.match(/\.js$/));
216 | return template({ css, js, ...data});
217 | }
218 | ```
219 |
220 | ## Specifying entry
221 |
222 | This plugin defaults to the first chunk found. While this should work in most cases, you can specify the entry name if needed:
223 |
224 | ```js
225 | module.exports = {
226 | ...,
227 | plugins: [
228 | new StaticSiteGeneratorPlugin({
229 | entry: 'main'
230 | })
231 | ]
232 | }
233 | ```
234 |
235 | ## Compression support
236 |
237 | Generated files can be compressed with [compression-webpack-plugin](https://github.com/webpack/compression-webpack-plugin), but first ensure that this plugin appears before compression-webpack-plugin in your plugins array:
238 |
239 | ```js
240 | const StaticSiteGeneratorPlugin = require('static-site-generator-webpack-plugin');
241 | const CompressionPlugin = require('compression-webpack-plugin');
242 |
243 | module.exports = {
244 | ...
245 |
246 | plugins: [
247 | new StaticSiteGeneratorPlugin(...),
248 | new CompressionPlugin(...)
249 | ]
250 | };
251 | ```
252 |
253 | ## Related projects
254 |
255 | - [react-router-to-array](https://github.com/alansouzati/react-router-to-array) - useful for avoiding hardcoded lists of routes to render
256 | - [gatsby](https://github.com/gatsbyjs/gatsby) - opinionated static site generator built on top of this plugin
257 |
258 | ## License
259 |
260 | [MIT License](http://markdalgleish.mit-license.org)
261 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var RawSource = require('webpack-sources/lib/RawSource');
2 | var evaluate = require('eval');
3 | var path = require('path');
4 | var cheerio = require('cheerio');
5 | var url = require('url');
6 | var Promise = require('bluebird');
7 |
8 | function StaticSiteGeneratorWebpackPlugin(options) {
9 | if (arguments.length > 1) {
10 | options = legacyArgsToOptions.apply(null, arguments);
11 | }
12 |
13 | options = options || {};
14 |
15 | this.entry = options.entry;
16 | this.paths = Array.isArray(options.paths) ? options.paths : [options.paths || '/'];
17 | this.locals = options.locals;
18 | this.globals = options.globals;
19 | this.crawl = Boolean(options.crawl);
20 | }
21 |
22 | StaticSiteGeneratorWebpackPlugin.prototype.apply = function(compiler) {
23 | var self = this;
24 |
25 | addThisCompilationHandler(compiler, function(compilation) {
26 | addOptimizeAssetsHandler(compilation, function(_, done) {
27 | var renderPromises;
28 |
29 | var webpackStats = compilation.getStats();
30 | var webpackStatsJson = webpackStats.toJson();
31 |
32 | try {
33 | var asset = findAsset(self.entry, compilation, webpackStatsJson);
34 |
35 | if (asset == null) {
36 | throw new Error('Source file not found: "' + self.entry + '"');
37 | }
38 |
39 | var assets = getAssetsFromCompilation(compilation, webpackStatsJson);
40 |
41 | var source = asset.source();
42 | var render = evaluate(source, /* filename: */ self.entry, /* scope: */ self.globals, /* includeGlobals: */ true);
43 |
44 | if (render.hasOwnProperty('default')) {
45 | render = render['default'];
46 | }
47 |
48 | if (typeof render !== 'function') {
49 | throw new Error('Export from "' + self.entry + '" must be a function that returns an HTML string. Is output.libraryTarget in the configuration set to "umd"?');
50 | }
51 |
52 | renderPaths(self.crawl, self.locals, self.paths, render, assets, webpackStats, compilation)
53 | .nodeify(done);
54 | } catch (err) {
55 | compilation.errors.push(err.stack);
56 | done();
57 | }
58 | });
59 | });
60 | };
61 |
62 | function renderPaths(crawl, userLocals, paths, render, assets, webpackStats, compilation) {
63 | var renderPromises = paths.map(function(outputPath) {
64 | var locals = {
65 | path: outputPath,
66 | assets: assets,
67 | webpackStats: webpackStats
68 | };
69 |
70 | for (var prop in userLocals) {
71 | if (userLocals.hasOwnProperty(prop)) {
72 | locals[prop] = userLocals[prop];
73 | }
74 | }
75 |
76 | var renderPromise = render.length < 2 ?
77 | Promise.resolve(render(locals)) :
78 | Promise.fromNode(render.bind(null, locals));
79 |
80 | return renderPromise
81 | .then(function(output) {
82 | var outputByPath = typeof output === 'object' ? output : makeObject(outputPath, output);
83 |
84 | var assetGenerationPromises = Object.keys(outputByPath).map(function(key) {
85 | var rawSource = outputByPath[key];
86 | var assetName = pathToAssetName(key);
87 |
88 | if (compilation.assets[assetName]) {
89 | return;
90 | }
91 |
92 | compilation.assets[assetName] = new RawSource(rawSource);
93 |
94 | if (crawl) {
95 | var relativePaths = relativePathsFromHtml({
96 | source: rawSource,
97 | path: key
98 | });
99 |
100 | return renderPaths(crawl, userLocals, relativePaths, render, assets, webpackStats, compilation);
101 | }
102 | });
103 |
104 | return Promise.all(assetGenerationPromises);
105 | })
106 | .catch(function(err) {
107 | compilation.errors.push(err.stack);
108 | });
109 | });
110 |
111 | return Promise.all(renderPromises);
112 | }
113 |
114 | var findAsset = function(src, compilation, webpackStatsJson) {
115 | if (!src) {
116 | var chunkNames = Object.keys(webpackStatsJson.assetsByChunkName);
117 |
118 | src = chunkNames[0];
119 | }
120 |
121 | var asset = compilation.assets[src];
122 |
123 | if (asset) {
124 | return asset;
125 | }
126 |
127 | var chunkValue = webpackStatsJson.assetsByChunkName[src];
128 |
129 | if (!chunkValue) {
130 | return null;
131 | }
132 | // Webpack outputs an array for each chunk when using sourcemaps
133 | if (chunkValue instanceof Array) {
134 | // Is the main bundle always the first element?
135 | chunkValue = chunkValue.find(function(filename) {
136 | return /\.js$/.test(filename);
137 | });
138 | }
139 | return compilation.assets[chunkValue];
140 | };
141 |
142 | // Shamelessly stolen from html-webpack-plugin - Thanks @ampedandwired :)
143 | var getAssetsFromCompilation = function(compilation, webpackStatsJson) {
144 | var assets = {};
145 | for (var chunk in webpackStatsJson.assetsByChunkName) {
146 | var chunkValue = webpackStatsJson.assetsByChunkName[chunk];
147 |
148 | // Webpack outputs an array for each chunk when using sourcemaps
149 | if (chunkValue instanceof Array) {
150 | // Is the main bundle always the first JS element?
151 | chunkValue = chunkValue.find(function(filename) {
152 | return /\.js$/.test(filename);
153 | });
154 | }
155 |
156 | if (compilation.options.output.publicPath) {
157 | chunkValue = compilation.options.output.publicPath + chunkValue;
158 | }
159 | assets[chunk] = chunkValue;
160 | }
161 |
162 | return assets;
163 | };
164 |
165 | function pathToAssetName(outputPath) {
166 | var outputFileName = outputPath.replace(/^(\/|\\)/, ''); // Remove leading slashes for webpack-dev-server
167 |
168 | if (!/\.(html?)$/i.test(outputFileName)) {
169 | outputFileName = path.join(outputFileName, 'index.html');
170 | }
171 |
172 | return outputFileName;
173 | }
174 |
175 | function makeObject(key, value) {
176 | var obj = {};
177 | obj[key] = value;
178 | return obj;
179 | }
180 |
181 | function relativePathsFromHtml(options) {
182 | var html = options.source;
183 | var currentPath = options.path;
184 |
185 | var $ = cheerio.load(html);
186 |
187 | var linkHrefs = $('a[href]')
188 | .map(function(i, el) {
189 | return $(el).attr('href');
190 | })
191 | .get();
192 |
193 | var iframeSrcs = $('iframe[src]')
194 | .map(function(i, el) {
195 | return $(el).attr('src');
196 | })
197 | .get();
198 |
199 | return []
200 | .concat(linkHrefs)
201 | .concat(iframeSrcs)
202 | .map(function(href) {
203 | if (href.indexOf('//') === 0) {
204 | return null
205 | }
206 |
207 | var parsed = url.parse(href);
208 |
209 | if (parsed.protocol || typeof parsed.path !== 'string') {
210 | return null;
211 | }
212 |
213 | return parsed.path.indexOf('/') === 0 ?
214 | parsed.path :
215 | url.resolve(currentPath, parsed.path);
216 | })
217 | .filter(function(href) {
218 | return href != null;
219 | });
220 | }
221 |
222 | function legacyArgsToOptions(entry, paths, locals, globals) {
223 | return {
224 | entry: entry,
225 | paths: paths,
226 | locals: locals,
227 | globals: globals
228 | };
229 | }
230 |
231 | function addThisCompilationHandler(compiler, callback) {
232 | if(compiler.hooks) {
233 | /* istanbul ignore next */
234 | compiler.hooks.thisCompilation.tap('static-site-generator-webpack-plugin', callback);
235 | } else {
236 | compiler.plugin('this-compilation', callback);
237 | }
238 | }
239 |
240 | function addOptimizeAssetsHandler(compilation, callback) {
241 | if(compilation.hooks) {
242 | /* istanbul ignore next */
243 | compilation.hooks.optimizeAssets.tapAsync('static-site-generator-webpack-plugin',callback);
244 | } else {
245 | compilation.plugin('optimize-assets', callback);
246 | }
247 | }
248 |
249 | module.exports = StaticSiteGeneratorWebpackPlugin;
250 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | coveragePathIgnorePatterns: ["/node_modules/", "/test/"]
3 | }
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "static-site-generator-webpack-plugin",
3 | "version": "3.4.2",
4 | "description": "Minimal, unopinionated static site generator powered by webpack",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "jest test",
8 | "coverage": "jest --coverage",
9 | "coveralls": "jest --coverage --coverageReporters=text-lcov | coveralls"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/markdalgleish/static-site-generator-webpack-plugin"
14 | },
15 | "author": "Mark Dalgleish",
16 | "license": "MIT",
17 | "bugs": {
18 | "url": "https://github.com/markdalgleish/static-site-generator-webpack-plugin/issues"
19 | },
20 | "homepage": "https://github.com/markdalgleish/static-site-generator-webpack-plugin",
21 | "dependencies": {
22 | "bluebird": "^3.0.5",
23 | "cheerio": "^0.22.0",
24 | "eval": "^0.1.0",
25 | "url": "^0.11.0",
26 | "webpack-sources": "^0.2.0"
27 | },
28 | "devDependencies": {
29 | "async": "^2.0.1",
30 | "babel-core": "^6.2.1",
31 | "babel-loader": "^6.2.0",
32 | "babel-preset-es2015": "^6.1.18",
33 | "compression-webpack-plugin": "^0.3.1",
34 | "coveralls": "^3.0.2",
35 | "dir-compare": "^1.4.0",
36 | "ejs": "^2.3.4",
37 | "es6-promisify": "^6.0.0",
38 | "glob": "^7.0.3",
39 | "jest": "^23.6.0",
40 | "node-dir": "^0.1.17",
41 | "rimraf": "^2.4.4",
42 | "webpack": "^1.12.10",
43 | "webpack-stats-plugin": "^0.1.1"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/__snapshots__/index.spec.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`Success cases basic should generate the expected files 1`] = `
4 | Object {
5 | "foo/bar/index.html": "
6 |
7 | /foo/bar
8 |
9 |
10 | ",
11 | "foo/index.html": "
12 |
13 | /foo
14 |
15 |
16 | ",
17 | "index.html": "
18 |
19 | /
20 |
21 |
22 | ",
23 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
24 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
25 | }
26 | `;
27 |
28 | exports[`Success cases basic-promise should generate the expected files 1`] = `
29 | Object {
30 | "foo/bar/index.html": "
31 |
32 | /foo/bar
33 |
34 |
35 | ",
36 | "foo/index.html": "
37 |
38 | /foo
39 |
40 |
41 | ",
42 | "index.html": "
43 |
44 | /
45 |
46 |
47 | ",
48 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
49 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
50 | }
51 | `;
52 |
53 | exports[`Success cases basic-sync should generate the expected files 1`] = `
54 | Object {
55 | "foo/bar/index.html": "
56 |
57 | /foo/bar
58 |
59 |
60 | ",
61 | "foo/index.html": "
62 |
63 | /foo
64 |
65 |
66 | ",
67 | "index.html": "
68 |
69 | /
70 |
71 |
72 | ",
73 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
74 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
75 | }
76 | `;
77 |
78 | exports[`Success cases compression should generate the expected files 1`] = `
79 | Object {
80 | "index.html": "
81 |
82 | /
83 |
84 |
85 | ",
86 | "index.html.gz": "CONTENTS IGNORED IN SNAPSHOT TEST",
87 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
88 | }
89 | `;
90 |
91 | exports[`Success cases crawl-ignore should generate the expected files 1`] = `
92 | Object {
93 | "index.html": "Don't crawl these:
94 |
100 | ",
101 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
102 | }
103 | `;
104 |
105 | exports[`Success cases crawl-relative should generate the expected files 1`] = `
106 | Object {
107 | "foo/bar/baz/index.html": "/foo/bar/baz
108 |
109 | Crawl this
110 | ",
111 | "foo/bar/index.html": "/foo/bar
112 |
113 | Crawl this
114 | ",
115 | "foo/index.html": "/foo
116 |
117 | Crawl this
118 | ",
119 | "index.html": "/
120 |
121 | Crawl this
122 | ",
123 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
124 | }
125 | `;
126 |
127 | exports[`Success cases crawl-relative-iframes should generate the expected files 1`] = `
128 | Object {
129 | "foo/bar/baz/index.html": "/foo/bar/baz
130 |
131 |
132 | ",
133 | "foo/bar/index.html": "/foo/bar
134 |
135 |
136 | ",
137 | "foo/index.html": "/foo
138 |
139 |
140 | ",
141 | "index.html": "/
142 |
143 |
144 | ",
145 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
146 | }
147 | `;
148 |
149 | exports[`Success cases crawl-root-relative should generate the expected files 1`] = `
150 | Object {
151 | "foo/bar/index.html": "/foo/bar
152 |
153 | Crawl this
154 | ",
155 | "foo/index.html": "/foo
156 |
157 | Crawl this
158 | ",
159 | "index.html": "/
160 |
161 | Crawl this
162 | ",
163 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
164 | }
165 | `;
166 |
167 | exports[`Success cases crawl-root-relative-iframes should generate the expected files 1`] = `
168 | Object {
169 | "foo/bar/index.html": "/foo/bar
170 |
171 |
172 | ",
173 | "foo/index.html": "/foo
174 |
175 |
176 | ",
177 | "index.html": "/
178 |
179 |
180 | ",
181 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
182 | }
183 | `;
184 |
185 | exports[`Success cases custom-file-names should generate the expected files 1`] = `
186 | Object {
187 | "custom.html": "
188 |
189 | /custom.html
190 |
191 |
192 | ",
193 | "foo/bar/custom.html": "
194 |
195 | /foo/bar/custom.html
196 |
197 |
198 | ",
199 | "foo/custom.html": "
200 |
201 | /foo/custom.html
202 |
203 |
204 | ",
205 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
206 | }
207 | `;
208 |
209 | exports[`Success cases default-entry-when-named should generate the expected files 1`] = `
210 | Object {
211 | "foo/bar/index.html": "
212 |
213 | /foo/bar
214 |
215 |
216 | ",
217 | "foo/index.html": "
218 |
219 | /foo
220 |
221 |
222 | ",
223 | "index.html": "
224 |
225 | /
226 |
227 |
228 | ",
229 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
230 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
231 | }
232 | `;
233 |
234 | exports[`Success cases entry-via-file-name should generate the expected files 1`] = `
235 | Object {
236 | "foo/bar/index.html": "
237 |
238 | /foo/bar
239 |
240 |
241 | ",
242 | "foo/index.html": "
243 |
244 | /foo
245 |
246 |
247 | ",
248 | "index.html": "
249 |
250 | /
251 |
252 |
253 | ",
254 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
255 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
256 | }
257 | `;
258 |
259 | exports[`Success cases entry-via-name should generate the expected files 1`] = `
260 | Object {
261 | "foo/bar/index.html": "
262 |
263 | /foo/bar
264 |
265 |
266 | ",
267 | "foo/index.html": "
268 |
269 | /foo
270 |
271 |
272 | ",
273 | "index.html": "
274 |
275 | /
276 |
277 |
278 | ",
279 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
280 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
281 | }
282 | `;
283 |
284 | exports[`Success cases es-modules should generate the expected files 1`] = `
285 | Object {
286 | "foo/bar/index.html": "
287 |
288 | /foo/bar
289 |
290 |
291 | ",
292 | "foo/index.html": "
293 |
294 | /foo
295 |
296 |
297 | ",
298 | "index.html": "
299 |
300 | /
301 |
302 |
303 | ",
304 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
305 | "index.js.map": "CONTENTS IGNORED IN SNAPSHOT TEST",
306 | }
307 | `;
308 |
309 | exports[`Success cases ignore-inherited-locals should generate the expected files 1`] = `
310 | Object {
311 | "index.html": "
312 |
313 | \\"DONT_INCLUDE_ME\\" is in locals: false
314 |
315 |
316 | ",
317 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
318 | }
319 | `;
320 |
321 | exports[`Success cases legacy-args should generate the expected files 1`] = `
322 | Object {
323 | "1.index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
324 | "foo/bar/index.html": "
325 |
326 | /foo/bar
327 |
328 |
329 | ",
330 | "foo/index.html": "
331 |
332 | /foo
333 |
334 |
335 | ",
336 | "index.html": "
337 |
338 | /
339 |
340 |
341 | ",
342 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
343 | }
344 | `;
345 |
346 | exports[`Success cases multi-render should generate the expected files 1`] = `
347 | Object {
348 | "foo/bar/index.html": "
349 |
350 | /foo/bar
351 |
352 |
353 | ",
354 | "foo/index.html": "
355 |
356 | /foo
357 |
358 |
359 | ",
360 | "index.html": "
361 |
362 | /
363 |
364 |
365 | ",
366 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
367 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
368 | }
369 | `;
370 |
371 | exports[`Success cases multi-render-custom-file-names should generate the expected files 1`] = `
372 | Object {
373 | "custom.html": "
374 |
375 | /custom.html
376 |
377 |
378 | ",
379 | "foo/bar/custom.html": "
380 |
381 | /foo/bar/custom.html
382 |
383 |
384 | ",
385 | "foo/custom.html": "
386 |
387 | /foo/custom.html
388 |
389 |
390 | ",
391 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
392 | }
393 | `;
394 |
395 | exports[`Success cases no-options-provided should generate the expected files 1`] = `
396 | Object {
397 | "index.html": "[\\"path\\",\\"assets\\",\\"webpackStats\\"]",
398 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
399 | "stats.json": "CONTENTS IGNORED IN SNAPSHOT TEST",
400 | }
401 | `;
402 |
403 | exports[`Success cases require-ensure should generate the expected files 1`] = `
404 | Object {
405 | "1.index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
406 | "foo/bar/index.html": "
407 |
408 | /foo/bar
409 |
410 |
411 | ",
412 | "foo/index.html": "
413 |
414 | /foo
415 |
416 |
417 | ",
418 | "index.html": "
419 |
420 | /
421 |
422 |
423 | ",
424 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
425 | }
426 | `;
427 |
428 | exports[`Success cases single-path should generate the expected files 1`] = `
429 | Object {
430 | "index.html": "
431 |
432 | /
433 |
434 |
435 | ",
436 | "index.js": "CONTENTS IGNORED IN SNAPSHOT TEST",
437 | }
438 | `;
439 |
--------------------------------------------------------------------------------
/test/error-cases/missing-source/expected-error.js:
--------------------------------------------------------------------------------
1 | module.exports = 'Error: Source file not found: "THIS_DOESNT_EXIST"';
2 |
--------------------------------------------------------------------------------
/test/error-cases/missing-source/index.js:
--------------------------------------------------------------------------------
1 | //This file intentionally left blank ;)
2 |
--------------------------------------------------------------------------------
/test/error-cases/missing-source/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 |
3 | module.exports = {
4 |
5 | entry: {
6 | main: __dirname + '/index.js'
7 | },
8 |
9 | output: {
10 | filename: 'index.js',
11 | path: __dirname + '/actual-output',
12 | publicPath: '/',
13 | libraryTarget: 'umd'
14 | },
15 |
16 | plugins: [
17 | new StaticSiteGeneratorPlugin('THIS_DOESNT_EXIST', ['/'])
18 | ]
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/test/error-cases/non-function-export/expected-error.js:
--------------------------------------------------------------------------------
1 | module.exports = 'Error: Export from "main" must be a function that returns an HTML string';
2 |
--------------------------------------------------------------------------------
/test/error-cases/non-function-export/index.js:
--------------------------------------------------------------------------------
1 | module.exports = 'Oops, this should be a function';
2 |
--------------------------------------------------------------------------------
/test/error-cases/non-function-export/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 |
3 | module.exports = {
4 |
5 | entry: {
6 | main: __dirname + '/index.js'
7 | },
8 |
9 | output: {
10 | filename: 'index.js',
11 | path: __dirname + '/actual-output',
12 | publicPath: '/',
13 | libraryTarget: 'umd'
14 | },
15 |
16 | plugins: [
17 | new StaticSiteGeneratorPlugin('main', ['/'])
18 | ]
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/test/error-cases/render-error/expected-error.js:
--------------------------------------------------------------------------------
1 | module.exports = 'path.NOT_A_FUNCTION is not a function';
2 |
--------------------------------------------------------------------------------
/test/error-cases/render-error/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(path, locals) {
2 | path.NOT_A_FUNCTION();
3 | };
4 |
--------------------------------------------------------------------------------
/test/error-cases/render-error/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 |
3 | module.exports = {
4 |
5 | entry: {
6 | main: __dirname + '/index.js'
7 | },
8 |
9 | output: {
10 | filename: 'index.js',
11 | path: __dirname + '/actual-output',
12 | publicPath: '/',
13 | libraryTarget: 'umd'
14 | },
15 |
16 | plugins: [
17 | new StaticSiteGeneratorPlugin('main', ['/'])
18 | ]
19 |
20 | };
21 |
--------------------------------------------------------------------------------
/test/index.spec.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const { promisify } = require('es6-promisify');
3 | const clean = require('rimraf');
4 | const dirCompare = require('dir-compare');
5 | const webpack = promisify(require('webpack'));
6 | const rimrafAsync = promisify(require('rimraf'));
7 | const getSubDirsSync = require('./utils/get-sub-dirs-sync');
8 | const dirContentsToObject = require('./utils/dir-contents-to-object');
9 | const directoryContains = require('./utils/directory-contains');
10 |
11 | const successCases = getSubDirsSync(__dirname + '/success-cases');
12 | const errorCases = getSubDirsSync(__dirname + '/error-cases');
13 |
14 | jest.setTimeout(20000);
15 |
16 | describe('Success cases', () => {
17 | getSubDirsSync(__dirname + '/success-cases').forEach(testCaseName => {
18 | describe(testCaseName, () => {
19 | const testCaseRoot = __dirname + '/success-cases/' + testCaseName;
20 |
21 | beforeAll(() => rimrafAsync(testCaseRoot + '/actual-output/'));
22 |
23 | it('should generate the expected files', () => {
24 | return webpack(require(path.join(testCaseRoot, 'webpack.config.js')))
25 | .then(() => dirContentsToObject(testCaseRoot + '/actual-output'))
26 | .then(files => {
27 | expect(files).toMatchSnapshot();
28 | });
29 | });
30 | });
31 | });
32 | });
33 |
34 | describe('Error cases', () => {
35 | errorCases.forEach(errorCase => {
36 | describe(errorCase, () => {
37 | beforeEach(() =>
38 | rimrafAsync(__dirname + '/error-cases/' + errorCase + '/actual-output')
39 | );
40 |
41 | it('generates the expected error', () => {
42 | const webpackConfig = require('./error-cases/' +
43 | errorCase +
44 | '/webpack.config.js');
45 | const expectedError = require('./error-cases/' +
46 | errorCase +
47 | '/expected-error.js');
48 |
49 | return webpack(webpackConfig).then(stats => {
50 | const actualError = stats.compilation.errors[0]
51 | .toString()
52 | .split('\n')[0];
53 | expect(actualError).toContain(expectedError);
54 | });
55 | });
56 | });
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/test/success-cases/basic-promise/index.js:
--------------------------------------------------------------------------------
1 | var Promise = require('bluebird');
2 |
3 | module.exports = function(locals) {
4 | return Promise.resolve(locals.template({ html: '' + locals.path + '
' }));
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/basic-promise/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/basic-promise/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: __dirname + '/index.js',
16 |
17 | output: {
18 | filename: 'index.js',
19 | path: __dirname + '/actual-output',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | paths: paths,
26 | locals: {
27 | template: template
28 | }
29 | }),
30 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
31 | ]
32 | };
33 |
--------------------------------------------------------------------------------
/test/success-cases/basic-sync/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | return locals.template({ html: '' + locals.path + '
' });
3 | };
4 |
--------------------------------------------------------------------------------
/test/success-cases/basic-sync/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/basic-sync/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: __dirname + '/index.js',
16 |
17 | output: {
18 | filename: 'index.js',
19 | path: __dirname + '/actual-output',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | paths: paths,
26 | locals: {
27 | template: template
28 | }
29 | }),
30 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
31 | ]
32 | };
33 |
--------------------------------------------------------------------------------
/test/success-cases/basic/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, locals.template({ html: '' + locals.path + '
' }));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/basic/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/basic/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: __dirname + '/index.js',
16 |
17 | output: {
18 | filename: 'index.js',
19 | path: __dirname + '/actual-output',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | paths: paths,
26 | locals: {
27 | template: template
28 | }
29 | }),
30 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
31 | ]
32 | };
33 |
--------------------------------------------------------------------------------
/test/success-cases/compression/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | callback(null, locals.template({ html: '' + locals.path + '
' }));
3 | };
4 |
--------------------------------------------------------------------------------
/test/success-cases/compression/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/compression/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var CompressionPlugin = require('compression-webpack-plugin');
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | locals: {
20 | template: template
21 | }
22 | }),
23 | new CompressionPlugin({
24 | asset: '[path].gz[query]',
25 | algorithm: 'gzip',
26 | test: /\.html$/,
27 | threshold: 0,
28 | minRatio: 999
29 | })
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-ignore/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | switch (locals.path) {
3 | case '/': {
4 | return locals.template({
5 | path: locals.path
6 | });
7 | }
8 | default: {
9 | return '404';
10 | }
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-ignore/template.ejs:
--------------------------------------------------------------------------------
1 | Don't crawl these:
2 |
8 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-ignore/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var templateSource = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
6 | var template = ejs.compile(templateSource);
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | crawl: true,
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative-iframes/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | switch (locals.path) {
3 | case '/': {
4 | return locals.template({
5 | path: locals.path,
6 | src: './foo'
7 | });
8 | }
9 | case '/foo': {
10 | return locals.template({
11 | path: locals.path,
12 | src: './foo/bar'
13 | });
14 | }
15 | case '/foo/bar': {
16 | return locals.template({
17 | path: locals.path,
18 | src: './bar/baz'
19 | });
20 | }
21 | case '/foo/bar/baz': {
22 | return locals.template({
23 | path: locals.path,
24 | src: 'javascript:void(0)'
25 | });
26 | }
27 | default: {
28 | return '404';
29 | }
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative-iframes/template.ejs:
--------------------------------------------------------------------------------
1 | <%= path %>
2 |
3 |
4 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative-iframes/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var templateSource = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
6 | var template = ejs.compile(templateSource);
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | crawl: true,
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | switch (locals.path) {
3 | case '/': {
4 | return locals.template({
5 | path: locals.path,
6 | link: 'foo'
7 | });
8 | }
9 | case '/foo': {
10 | return locals.template({
11 | path: locals.path,
12 | link: './foo/bar'
13 | });
14 | }
15 | case '/foo/bar': {
16 | return locals.template({
17 | path: locals.path,
18 | link: './bar/baz'
19 | });
20 | }
21 | case '/foo/bar/baz': {
22 | return locals.template({
23 | path: locals.path,
24 | link: '../../../'
25 | });
26 | }
27 | default: {
28 | return '404';
29 | }
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative/template.ejs:
--------------------------------------------------------------------------------
1 | <%= path %>
2 |
3 | Crawl this
4 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-relative/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var templateSource = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
6 | var template = ejs.compile(templateSource);
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | crawl: true,
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative-iframes/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | switch (locals.path) {
3 | case '/': {
4 | return locals.template({
5 | path: locals.path,
6 | src: '/foo'
7 | });
8 | }
9 | case '/foo': {
10 | return locals.template({
11 | path: locals.path,
12 | src: '/foo/bar'
13 | });
14 | }
15 | case '/foo/bar': {
16 | return locals.template({
17 | path: locals.path,
18 | src: 'javascript:void(0)'
19 | });
20 | }
21 | default: {
22 | return '404';
23 | }
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative-iframes/template.ejs:
--------------------------------------------------------------------------------
1 | <%= path %>
2 |
3 |
4 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative-iframes/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var templateSource = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
6 | var template = ejs.compile(templateSource);
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | crawl: true,
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | switch (locals.path) {
3 | case '/': {
4 | return locals.template({
5 | path: locals.path,
6 | link: '/foo'
7 | });
8 | }
9 | case '/foo': {
10 | return locals.template({
11 | path: locals.path,
12 | link: '/foo/bar'
13 | });
14 | }
15 | case '/foo/bar': {
16 | return locals.template({
17 | path: locals.path,
18 | link: '/'
19 | });
20 | }
21 | default: {
22 | return '404';
23 | }
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative/template.ejs:
--------------------------------------------------------------------------------
1 | <%= path %>
2 |
3 | Crawl this
4 |
--------------------------------------------------------------------------------
/test/success-cases/crawl-root-relative/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var templateSource = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
6 | var template = ejs.compile(templateSource);
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | crawl: true,
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/custom-file-names/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, locals.template({ html: '' + locals.path + '
' }));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/custom-file-names/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/custom-file-names/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | var paths = [
8 | '/custom.html',
9 | '/foo/custom.html',
10 | '/foo/bar/custom.html'
11 | ];
12 |
13 | module.exports = {
14 | entry: __dirname + '/index.js',
15 |
16 | output: {
17 | filename: 'index.js',
18 | path: __dirname + '/actual-output',
19 | publicPath: '/',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | paths: paths,
26 | locals: {
27 | template: template
28 | }
29 | })
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/test/success-cases/default-entry-when-named/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, locals.template({ html: '' + locals.path + '
' }));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/default-entry-when-named/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/default-entry-when-named/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: {
16 | CUSTOM_CHUNK_NAME: __dirname + '/index.js'
17 | },
18 |
19 | output: {
20 | filename: 'index.js',
21 | path: __dirname + '/actual-output',
22 | libraryTarget: 'umd'
23 | },
24 |
25 | plugins: [
26 | new StaticSiteGeneratorPlugin({
27 | paths: paths,
28 | locals: {
29 | template: template
30 | }
31 | }),
32 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
33 | ]
34 | };
35 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-file-name/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, locals.template({ html: '' + locals.path + '
' }));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-file-name/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-file-name/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: __dirname + '/index.js',
16 |
17 | output: {
18 | filename: 'index.js',
19 | path: __dirname + '/actual-output',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | entry: 'index.js',
26 | paths: paths,
27 | locals: {
28 | template: template
29 | }
30 | }),
31 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
32 | ]
33 | };
34 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-name/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, locals.template({ html: '' + locals.path + '
' }));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-name/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/entry-via-name/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | var paths = [
9 | '/',
10 | '/foo',
11 | '/foo/bar'
12 | ];
13 |
14 | module.exports = {
15 | entry: {
16 | CUSTOM_NAME: __dirname + '/index.js'
17 | },
18 |
19 | output: {
20 | filename: 'index.js',
21 | path: __dirname + '/actual-output',
22 | libraryTarget: 'umd'
23 | },
24 |
25 | plugins: [
26 | new StaticSiteGeneratorPlugin({
27 | entry: 'CUSTOM_NAME',
28 | paths: paths,
29 | locals: {
30 | template: template
31 | }
32 | }),
33 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
34 | ]
35 | };
36 |
--------------------------------------------------------------------------------
/test/success-cases/es-modules/index.js:
--------------------------------------------------------------------------------
1 | export default ({ template, path }, callback) => {
2 | const html = `${path}
`;
3 | const content = template({ html });
4 | setTimeout(() => callback(null, content), 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/es-modules/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/es-modules/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | var paths = [
8 | '/',
9 | '/foo',
10 | '/foo/bar'
11 | ];
12 |
13 | module.exports = {
14 | entry: __dirname + '/index.js',
15 |
16 | output: {
17 | filename: 'index.js',
18 | path: __dirname + '/actual-output',
19 | publicPath: '/',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | module: {
24 | loaders: [
25 | {
26 | test: /\.js$/,
27 | exclude: /node_modules/,
28 | loader: 'babel',
29 | query: {
30 | presets: ['es2015']
31 | }
32 | }
33 | ]
34 | },
35 |
36 | devtool: 'source-map',
37 |
38 | plugins: [
39 | new StaticSiteGeneratorPlugin({
40 | paths: paths,
41 | locals: {
42 | template: template
43 | }
44 | })
45 | ]
46 | };
47 |
--------------------------------------------------------------------------------
/test/success-cases/ignore-inherited-locals/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | callback(null, locals.template({ html: '"DONT_INCLUDE_ME" is in locals: ' + ('DONT_INCLUDE_ME' in locals) + '
' }));
3 | };
4 |
--------------------------------------------------------------------------------
/test/success-cases/ignore-inherited-locals/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/ignore-inherited-locals/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | var localsProto = { DONT_INCLUDE_ME: true };
8 | var locals = Object.create(localsProto);
9 | locals.template = template;
10 |
11 | module.exports = {
12 | entry: __dirname + '/index.js',
13 |
14 | output: {
15 | filename: 'index.js',
16 | path: __dirname + '/actual-output',
17 | publicPath: '/',
18 | libraryTarget: 'umd'
19 | },
20 |
21 | plugins: [
22 | new StaticSiteGeneratorPlugin({
23 | locals: locals
24 | })
25 | ]
26 | };
27 |
--------------------------------------------------------------------------------
/test/success-cases/legacy-args/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = 'Foo';
2 |
--------------------------------------------------------------------------------
/test/success-cases/legacy-args/index.js:
--------------------------------------------------------------------------------
1 | // Do not actually call this function, because executing require.ensure requires a 'document'.
2 | function dontDoIt() {
3 | require.ensure([], function() {
4 | var foo = require('./foo');
5 | });
6 | }
7 |
8 | module.exports = function(locals, callback) {
9 | setTimeout(function() {
10 | callback(null, locals.template({ html: '' + locals.path + '
' }));
11 | }, 10);
12 |
13 | };
14 |
--------------------------------------------------------------------------------
/test/success-cases/legacy-args/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/legacy-args/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | var paths = [
8 | '/',
9 | '/foo',
10 | '/foo/bar'
11 | ];
12 |
13 | module.exports = {
14 | entry: {
15 | main: __dirname + '/index.js'
16 | },
17 |
18 | output: {
19 | filename: 'index.js',
20 | path: __dirname + '/actual-output',
21 | publicPath: '/',
22 | libraryTarget: 'umd'
23 | },
24 |
25 | plugins: [
26 | new StaticSiteGeneratorPlugin('main', paths, { template: template }, { window: {} })
27 | ]
28 | };
29 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render-custom-file-names/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | function template(path) {
3 | return locals.template({ html: '' + path + '
' });
4 | }
5 |
6 | return {
7 | '/custom.html': template('/custom.html'),
8 | '/foo/custom.html': template('/foo/custom.html'),
9 | '/foo/bar/custom.html': template('/foo/bar/custom.html')
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render-custom-file-names/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render-custom-file-names/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | module.exports = {
8 | entry: __dirname + '/index.js',
9 |
10 | output: {
11 | filename: 'index.js',
12 | path: __dirname + '/actual-output',
13 | publicPath: '/',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | locals: {
20 | template: template
21 | }
22 | })
23 | ]
24 | };
25 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals) {
2 | function template(path) {
3 | return locals.template({ html: '' + path + '
' });
4 | }
5 |
6 | return {
7 | '/': template('/'),
8 | '/foo': template('/foo'),
9 | '/foo/bar': template('/foo/bar')
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/multi-render/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 | var ejs = require('ejs');
4 | var fs = require('fs');
5 |
6 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
7 |
8 | module.exports = {
9 | entry: __dirname + '/index.js',
10 |
11 | output: {
12 | filename: 'index.js',
13 | path: __dirname + '/actual-output',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | locals: {
20 | template: template
21 | }
22 | }),
23 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/success-cases/no-options-provided/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | setTimeout(function() {
3 | callback(null, JSON.stringify(Object.keys(locals)));
4 | }, 10);
5 | };
6 |
--------------------------------------------------------------------------------
/test/success-cases/no-options-provided/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var StatsWriterPlugin = require("webpack-stats-plugin").StatsWriterPlugin;
3 |
4 | module.exports = {
5 | entry: __dirname + '/index.js',
6 |
7 | output: {
8 | filename: 'index.js',
9 | path: __dirname + '/actual-output',
10 | libraryTarget: 'umd'
11 | },
12 |
13 | plugins: [
14 | new StaticSiteGeneratorPlugin(),
15 | new StatsWriterPlugin() // Causes the asset's `size` method to be called
16 | ]
17 | };
18 |
--------------------------------------------------------------------------------
/test/success-cases/require-ensure/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = 'Foo';
2 |
--------------------------------------------------------------------------------
/test/success-cases/require-ensure/index.js:
--------------------------------------------------------------------------------
1 | // Do not actually call this function, because executing require.ensure requires a 'document'.
2 | function dontDoIt() {
3 | require.ensure([], function() {
4 | var foo = require('./foo');
5 | });
6 | }
7 |
8 | module.exports = function(locals, callback) {
9 | setTimeout(function() {
10 | callback(null, locals.template({ html: '' + locals.path + '
' }));
11 | }, 10);
12 |
13 | };
14 |
--------------------------------------------------------------------------------
/test/success-cases/require-ensure/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/require-ensure/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | var paths = [
8 | '/',
9 | '/foo',
10 | '/foo/bar'
11 | ];
12 |
13 | module.exports = {
14 | entry: __dirname + '/index.js',
15 |
16 | output: {
17 | filename: 'index.js',
18 | path: __dirname + '/actual-output',
19 | publicPath: '/',
20 | libraryTarget: 'umd'
21 | },
22 |
23 | plugins: [
24 | new StaticSiteGeneratorPlugin({
25 | paths: paths,
26 | locals: {
27 | template: template
28 | },
29 | globals: {
30 | window: {}
31 | }
32 | })
33 | ]
34 | };
35 |
--------------------------------------------------------------------------------
/test/success-cases/single-path/index.js:
--------------------------------------------------------------------------------
1 | module.exports = function(locals, callback) {
2 | callback(null, locals.template({ html: '' + locals.path + '
' }));
3 | };
4 |
--------------------------------------------------------------------------------
/test/success-cases/single-path/template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 | <%- html %>
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/success-cases/single-path/webpack.config.js:
--------------------------------------------------------------------------------
1 | var StaticSiteGeneratorPlugin = require('../../../');
2 | var ejs = require('ejs');
3 | var fs = require('fs');
4 |
5 | var template = ejs.compile(fs.readFileSync(__dirname + '/template.ejs', 'utf-8'))
6 |
7 | module.exports = {
8 | entry: __dirname + '/index.js',
9 |
10 | output: {
11 | filename: 'index.js',
12 | path: __dirname + '/actual-output',
13 | publicPath: '/',
14 | libraryTarget: 'umd'
15 | },
16 |
17 | plugins: [
18 | new StaticSiteGeneratorPlugin({
19 | paths: '/',
20 | locals: {
21 | template: template
22 | }
23 | })
24 | ]
25 | };
26 |
--------------------------------------------------------------------------------
/test/utils/dir-contents-to-object.js:
--------------------------------------------------------------------------------
1 | const { promisify } = require('es6-promisify');
2 | const readFilesAsync = promisify(require('node-dir').readFiles);
3 | const { relative } = require('path');
4 |
5 | module.exports = dirname => {
6 | const files = {};
7 |
8 | const handleFile = (err, content, filePath, next) => {
9 | if (err) throw err;
10 |
11 | const relativeFilePath = relative(dirname, filePath);
12 |
13 | files[relativeFilePath] = /\.html?$/.test(relativeFilePath)
14 | ? content
15 | : 'CONTENTS IGNORED IN SNAPSHOT TEST';
16 |
17 | next();
18 | };
19 |
20 | return readFilesAsync(dirname, handleFile).then(() => files);
21 | };
22 |
--------------------------------------------------------------------------------
/test/utils/directory-contains.js:
--------------------------------------------------------------------------------
1 | var glob = require('glob');
2 | var async = require('async');
3 | var fs = require('fs');
4 | var path = require('path');
5 |
6 | var readFile = function(path, done) {
7 | return fs.readFile(path, 'utf8', done);
8 | };
9 |
10 | module.exports = function(referenceDir, targetDir, done) {
11 | var compareFile = function(file, done) {
12 | var referenceFile = path.join(referenceDir, file);
13 | var targetFile = path.join(targetDir, file);
14 |
15 | async.map([referenceFile, targetFile], readFile, function(err, results) {
16 | if (err) {
17 | return done(err);
18 | }
19 |
20 | done(null, results[0] === results[1]);
21 | });
22 | };
23 |
24 | glob('**/*', { cwd: referenceDir, nodir: true }, function(err, files) {
25 | if (err) {
26 | return done(err);
27 | }
28 |
29 | async.map(files, compareFile, function(err, results) {
30 | if (err) {
31 | return done(err);
32 | }
33 |
34 | done(null, !results.some(function(result) { return !result; }));
35 | });
36 | });
37 | };
38 |
--------------------------------------------------------------------------------
/test/utils/get-sub-dirs-sync.js:
--------------------------------------------------------------------------------
1 | var glob = require('glob');
2 |
3 | module.exports = function(cwd) {
4 | return glob.sync('*/', { cwd: cwd }).map(function(subDir) {
5 | return subDir.replace(/\/$/, '');
6 | });
7 | };
8 |
--------------------------------------------------------------------------------