diff --git a/bin/config-yargs.js b/bin/config-yargs.js index c7ca20a2b67..ac2187e350d 100644 --- a/bin/config-yargs.js +++ b/bin/config-yargs.js @@ -28,6 +28,16 @@ module.exports = function(yargs) { "Migrate your webpack configuration from webpack 1 to webpack 2", group: INIT_GROUP }, + "generate-loader": { + type: "boolean", + describe: "Generates a new webpack loader project", + group: INIT_GROUP + }, + "generate-plugin": { + type: "boolean", + describe: "Generates a new webpack plugin project", + group: INIT_GROUP + }, config: { type: "string", describe: "Path to the config file", diff --git a/bin/webpack.js b/bin/webpack.js index 19e31709f9a..db514c3f362 100755 --- a/bin/webpack.js +++ b/bin/webpack.js @@ -159,11 +159,11 @@ if (argv.verbose) { argv["display-cached"] = true; argv["display-cached-assets"] = true; } -if (argv._.includes("init")) { +if (argv._.indexOf("init") >= 0) { const initPkgs = argv._.length === 1 ? [] : [argv._.pop()]; return require("../lib/initialize")(initPkgs); -} else if (argv._.includes("migrate")) { +} else if (argv._.indexOf("migrate") >= 0) { const filePaths = argv._.length === 1 ? [] : [argv._.pop()]; if (!filePaths.length) { throw new Error("Please specify a path to your webpack config"); @@ -171,6 +171,10 @@ if (argv._.includes("init")) { const inputConfigPath = path.resolve(process.cwd(), filePaths[0]); return require("../lib/migrate.js")(inputConfigPath, inputConfigPath); +} else if (argv._.indexOf("generate-loader") >= 0) { + return require("../lib/generate-loader/index.js")(); +} else if (argv._.indexOf("generate-plugin") >= 0) { + return require("../lib/generate-plugin/index.js")(); } else { var options = require("./convert-argv")(yargs, argv); diff --git a/lib/generate-loader/index.js b/lib/generate-loader/index.js new file mode 100644 index 00000000000..ff83f5f84fa --- /dev/null +++ b/lib/generate-loader/index.js @@ -0,0 +1,17 @@ +var yeoman = require("yeoman-environment"); +var LoaderGenerator = require("./loader-generator").LoaderGenerator; + +/** + * Runs a yeoman generator to create a new webpack loader project + * @returns {void} + */ +function loaderCreator() { + var env = yeoman.createEnv(); + var generatorName = "webpack-loader-generator"; + + env.registerStub(LoaderGenerator, generatorName); + + env.run(generatorName); +} + +module.exports = loaderCreator; diff --git a/lib/generate-loader/loader-generator.js b/lib/generate-loader/loader-generator.js new file mode 100644 index 00000000000..9e5a22e27b5 --- /dev/null +++ b/lib/generate-loader/loader-generator.js @@ -0,0 +1,58 @@ +var path = require("path"); +var _ = require("lodash"); +var webpackGenerator = require("../utils/webpack-generator"); + +/** + * Formats a string into webpack loader format + * (eg: 'style-loader', 'raw-loader') + * + * @param {string} name A loader name to be formatted + * @returns {string} The formatted string + */ +function makeLoaderName(name) { + name = _.kebabCase(name); + if (!/loader$/.test(name)) { + name += "-loader"; + } + return name; +} + +/** + * A yeoman generator class for creating a webpack + * loader project. It adds some starter loader code + * and runs `webpack-defaults`. + * + * @class LoaderGenerator + * @extends {Generator} + */ +var LoaderGenerator = webpackGenerator( + [{ + type: "input", + name: "name", + message: "Loader name", + default: "my-loader", + filter: makeLoaderName, + validate: str => str.length > 0, + }], + path.join(__dirname, "templates"), + [ + "src/cjs.js.tpl", + "test/test-utils.js.tpl", + "test/unit.test.js.tpl", + "test/functional.test.js.tpl", + "test/fixtures/simple-file.js.tpl", + "examples/simple/webpack.config.js.tpl", + "examples/simple/src/index.js.tpl", + "examples/simple/src/lazy-module.js.tpl", + "examples/simple/src/static-esm-module.js.tpl", + ], + [ + "src/_index.js.tpl", + ], + (gen) => ({ name: gen.props.name }) +); + +module.exports = { + makeLoaderName, + LoaderGenerator, +}; diff --git a/lib/generate-loader/loader-generator.test.js b/lib/generate-loader/loader-generator.test.js new file mode 100644 index 00000000000..3dc3e55dd7e --- /dev/null +++ b/lib/generate-loader/loader-generator.test.js @@ -0,0 +1,17 @@ +"use strict"; + +var makeLoaderName = require("./loader-generator").makeLoaderName; + +describe("makeLoaderName", () => { + + it("should kebab-case loader name and append '-loader'", () => { + var loaderName = makeLoaderName("This is a test"); + expect(loaderName).toEqual("this-is-a-test-loader"); + }); + + it("should not modify a properly formatted loader name", () => { + var loaderName = makeLoaderName("properly-named-loader"); + expect(loaderName).toEqual("properly-named-loader"); + }); + +}); diff --git a/lib/generate-loader/templates/examples/simple/src/index.js.tpl b/lib/generate-loader/templates/examples/simple/src/index.js.tpl new file mode 100644 index 00000000000..2c49d366408 --- /dev/null +++ b/lib/generate-loader/templates/examples/simple/src/index.js.tpl @@ -0,0 +1,11 @@ +import esmModule from './static-esm-module'; + +const getLazyModule = () => System.import('./lazy-module'); + +setTimeout(() => { + getLazyModule.then((modDefault) => { + console.log(modDefault); + }); +}, 300); + +console.log(esmModule); diff --git a/lib/generate-loader/templates/examples/simple/src/lazy-module.js.tpl b/lib/generate-loader/templates/examples/simple/src/lazy-module.js.tpl new file mode 100644 index 00000000000..f3dac067326 --- /dev/null +++ b/lib/generate-loader/templates/examples/simple/src/lazy-module.js.tpl @@ -0,0 +1 @@ +export default 'lazy'; diff --git a/lib/generate-loader/templates/examples/simple/src/static-esm-module.js.tpl b/lib/generate-loader/templates/examples/simple/src/static-esm-module.js.tpl new file mode 100644 index 00000000000..d02ba545bd3 --- /dev/null +++ b/lib/generate-loader/templates/examples/simple/src/static-esm-module.js.tpl @@ -0,0 +1 @@ +export default 'foo'; diff --git a/lib/generate-loader/templates/examples/simple/webpack.config.js.tpl b/lib/generate-loader/templates/examples/simple/webpack.config.js.tpl new file mode 100644 index 00000000000..75b6744b7a2 --- /dev/null +++ b/lib/generate-loader/templates/examples/simple/webpack.config.js.tpl @@ -0,0 +1,27 @@ +const path = require('path'); + +module.exports = { + entry: './src/index.js', + output: { + path: path.join(__dirname, 'example_dist'), + filename: '[name].chunk.js', + }, + module: { + rules: [ + { + test: /\.js$/, + use: [ + { + loader: 'example-loader', + options: {}, + }, + ], + }, + ], + }, + resolveLoader: { + alias: { + 'example-loader': require.resolve('../../src/'), + }, + }, +}; diff --git a/lib/generate-loader/templates/src/_index.js.tpl b/lib/generate-loader/templates/src/_index.js.tpl new file mode 100644 index 00000000000..c69d5d329a6 --- /dev/null +++ b/lib/generate-loader/templates/src/_index.js.tpl @@ -0,0 +1,25 @@ +/** + * See the webpack docs for more information about loaders: + * https://github.com/webpack/docs/wiki/how-to-write-a-loader + */ + +export default function loader(source) { + const { loaders, resource, request, version, webpack } = this; + + const newSource = ` + /** + * <%= name %> + * + * Resource Location: ${resource} + * Loaders chained to module: ${JSON.stringify(loaders)} + * Loader API Version: ${version} + * Is this in "webpack mode": ${webpack} + * This is the users request for the module: ${request} + */ + /** + * Original Source From Loader + */ + ${source}`; + + return newSource; +} diff --git a/lib/generate-loader/templates/src/cjs.js.tpl b/lib/generate-loader/templates/src/cjs.js.tpl new file mode 100644 index 00000000000..82657ce3a74 --- /dev/null +++ b/lib/generate-loader/templates/src/cjs.js.tpl @@ -0,0 +1 @@ +module.exports = require('./index').default; diff --git a/lib/generate-loader/templates/test/fixtures/simple-file.js.tpl b/lib/generate-loader/templates/test/fixtures/simple-file.js.tpl new file mode 100644 index 00000000000..908ed137dff --- /dev/null +++ b/lib/generate-loader/templates/test/fixtures/simple-file.js.tpl @@ -0,0 +1,3 @@ +import foo from "./foo"; // eslint-disable-line + +console.log(foo); diff --git a/lib/generate-loader/templates/test/functional.test.js.tpl b/lib/generate-loader/templates/test/functional.test.js.tpl new file mode 100644 index 00000000000..b69f8d7f17a --- /dev/null +++ b/lib/generate-loader/templates/test/functional.test.js.tpl @@ -0,0 +1,21 @@ +import { + runWebpackExampleInMemory, +} from '../test/test-utils'; + +test('should run with no errors or warnings', async () => { + const buildStats = await runWebpackExampleInMemory('simple'); + const { errors, warnings } = buildStats; + + expect([...errors, ...warnings].length).toBe(0); +}); + +test('should append transformations to JavaScript module', async () => { + const buildStats = await runWebpackExampleInMemory('simple'); + const { modules } = buildStats; + + const moduleToTest = modules[0].source()._source._value; + const loadedString = '* Original Source From Loader'; + + expect(moduleToTest).toEqual(expect.stringContaining(loadedString)); + expect(moduleToTest).toMatchSnapshot(); +}); diff --git a/lib/generate-loader/templates/test/test-utils.js.tpl b/lib/generate-loader/templates/test/test-utils.js.tpl new file mode 100644 index 00000000000..bf8116f065f --- /dev/null +++ b/lib/generate-loader/templates/test/test-utils.js.tpl @@ -0,0 +1,82 @@ +import path from 'path'; +import webpack from 'webpack'; +import Promise from 'bluebird'; +import MemoryFs from 'memory-fs'; + +const fs = new MemoryFs(); +const unitTestFixtures = path.resolve(__dirname, 'fixtures'); + +/** + * + * + * @param {string} fixtureName + * @param {string} [withQueryString=''] + * @returns {string} Absolute path of a file with query that is to be run by a loader. + */ +function getFixtureResource(fixtureName, withQueryString = '') { + return `${getFixture(fixtureName)}?${withQueryString}`; +} + +/** + * + * + * @param {string} fixtureName + * @returns {string} Absolute path of a file with query that is to be run by a loader. + */ +function getFixture(fixtureName) { + return path.resolve(unitTestFixtures, `${fixtureName}.js`); +} + +/** + * + * + * @param {Object} withOptions - Loader Options + * @returns {{loader: string, options: Object}} + */ +function getLoader(withOptions) { + return [{ loader: path.resolve(__dirname, '../dist/index.js'), options: withOptions }]; +} + +/** + * + * + * @param {string} exampleName + * @returns {Object|Array} - Returns an object or array of objects representing the webpack configuration options + */ +function getExampleConfig(exampleName) { + return require(`../examples/${exampleName}/webpack.config.js`); +} + +/** + * + * + * @param {string} exampleName - name of example inside of examples folder + * @returns + */ +async function runWebpackExampleInMemory(exampleName) { + const webpackConfig = getExampleConfig(exampleName); + const compiler = webpack(webpackConfig); + + compiler.outputFileSystem = fs; + + const run = Promise.promisify(compiler.run, { context: compiler }); + const stats = await run(); + + + const { compilation } = stats; + const { errors, warnings, assets, entrypoints, chunks, modules } = compilation; + const statsJson = stats.toJson(); + + return { + assets, + entrypoints, + errors, + warnings, + stats, + chunks, + modules, + statsJson, + }; +} + +export { getExampleConfig, runWebpackExampleInMemory, fs, getFixtureResource, getLoader, getFixture }; diff --git a/lib/generate-loader/templates/test/unit.test.js.tpl b/lib/generate-loader/templates/test/unit.test.js.tpl new file mode 100644 index 00000000000..ac1b90a4e4a --- /dev/null +++ b/lib/generate-loader/templates/test/unit.test.js.tpl @@ -0,0 +1,32 @@ +import fs from 'fs'; +import Promise from 'bluebird'; +import { runLoaders } from 'loader-runner'; +import { getFixtureResource, getFixture, getLoader } from './test-utils'; + +const runLoadersPromise = Promise.promisify(runLoaders); +const readFilePromise = Promise.promisify(fs.readFile, { context: fs }); + + +const loaders = getLoader(); + +describe('Example Loader Tests: Fixture: simple-file', () => { + const fixtureName = 'simple-file'; + const resource = getFixture(fixtureName); + + test('loaded file should be different', async () => { + const originalSource = await readFilePromise(resource); + const { result } = await runLoadersPromise({ resource: getFixtureResource(fixtureName), loaders }); + + expect(result).not.toEqual(originalSource); + }); + + test('loader prepends correct information', async () => { + const { result } = await runLoadersPromise({ resource: getFixtureResource(fixtureName), loaders }); + const resultMatcher = expect.arrayContaining([ + expect.stringContaining(' * Original Source From Loader'), + ]); + + expect(result).toEqual(resultMatcher); + expect(result).toMatchSnapshot(); + }); +}); diff --git a/lib/generate-plugin/index.js b/lib/generate-plugin/index.js new file mode 100644 index 00000000000..82fe7dd386d --- /dev/null +++ b/lib/generate-plugin/index.js @@ -0,0 +1,17 @@ +var yeoman = require("yeoman-environment"); +var PluginGenerator = require("./plugin-generator").PluginGenerator; + +/** + * Runs a yeoman generator to create a new webpack plugin project + * @returns {void} + */ +function pluginCreator() { + var env = yeoman.createEnv(); + var generatorName = "webpack-plugin-generator"; + + env.registerStub(PluginGenerator, generatorName); + + env.run(generatorName); +} + +module.exports = pluginCreator; diff --git a/lib/generate-plugin/plugin-generator.js b/lib/generate-plugin/plugin-generator.js new file mode 100644 index 00000000000..fcddd43993a --- /dev/null +++ b/lib/generate-plugin/plugin-generator.js @@ -0,0 +1,40 @@ +var path = require("path"); +var _ = require("lodash"); +var webpackGenerator = require("../utils/webpack-generator"); + +/** + * A yeoman generator class for creating a webpack + * plugin project. It adds some starter plugin code + * and runs `webpack-defaults`. + * + * @class PluginGenerator + * @extends {Generator} + */ +var PluginGenerator = webpackGenerator( + [{ + type: "input", + name: "name", + message: "Plugin name", + default: "my-webpack-plugin", + filter: _.kebabCase, + validate: str => str.length > 0, + }], + path.join(__dirname, "templates"), + [ + "src/cjs.js.tpl", + "test/test-utils.js.tpl", + "test/functional.test.js.tpl", + "examples/simple/src/index.js.tpl", + "examples/simple/src/lazy-module.js.tpl", + "examples/simple/src/static-esm-module.js.tpl", + ], + [ + "src/_index.js.tpl", + "examples/simple/_webpack.config.js.tpl", + ], + (gen) => ({ name: _.upperFirst(_.camelCase(gen.props.name)) }) +); + +module.exports = { + PluginGenerator, +}; diff --git a/lib/generate-plugin/templates/examples/simple/_webpack.config.js.tpl b/lib/generate-plugin/templates/examples/simple/_webpack.config.js.tpl new file mode 100644 index 00000000000..e50ecc3e588 --- /dev/null +++ b/lib/generate-plugin/templates/examples/simple/_webpack.config.js.tpl @@ -0,0 +1,13 @@ +const path = require('path'); +const <%= name %> = require('../../src/index.js'); + +module.exports = { + entry: './src/index.js', + output: { + path: path.join(__dirname, 'example_dist'), + filename: '[name].chunk.js', + }, + plugins: [ + new <%= name %>() + ] +}; diff --git a/lib/generate-plugin/templates/examples/simple/src/index.js.tpl b/lib/generate-plugin/templates/examples/simple/src/index.js.tpl new file mode 100644 index 00000000000..2c49d366408 --- /dev/null +++ b/lib/generate-plugin/templates/examples/simple/src/index.js.tpl @@ -0,0 +1,11 @@ +import esmModule from './static-esm-module'; + +const getLazyModule = () => System.import('./lazy-module'); + +setTimeout(() => { + getLazyModule.then((modDefault) => { + console.log(modDefault); + }); +}, 300); + +console.log(esmModule); diff --git a/lib/generate-plugin/templates/examples/simple/src/lazy-module.js.tpl b/lib/generate-plugin/templates/examples/simple/src/lazy-module.js.tpl new file mode 100644 index 00000000000..f3dac067326 --- /dev/null +++ b/lib/generate-plugin/templates/examples/simple/src/lazy-module.js.tpl @@ -0,0 +1 @@ +export default 'lazy'; diff --git a/lib/generate-plugin/templates/examples/simple/src/static-esm-module.js.tpl b/lib/generate-plugin/templates/examples/simple/src/static-esm-module.js.tpl new file mode 100644 index 00000000000..d02ba545bd3 --- /dev/null +++ b/lib/generate-plugin/templates/examples/simple/src/static-esm-module.js.tpl @@ -0,0 +1 @@ +export default 'foo'; diff --git a/lib/generate-plugin/templates/src/_index.js.tpl b/lib/generate-plugin/templates/src/_index.js.tpl new file mode 100644 index 00000000000..1a9001b8d67 --- /dev/null +++ b/lib/generate-plugin/templates/src/_index.js.tpl @@ -0,0 +1,16 @@ +/** + * See the webpack docs for more information about plugins: + * https://github.com/webpack/docs/wiki/how-to-write-a-plugin + */ + +function <%= name %>(options) { + // Setup the plugin instance with options... +} + +<%= name %>.prototype.apply = function(compiler) { + compiler.plugin('done', function() { + console.log('Hello World!'); + }); +}; + +module.exports = <%= name %>; diff --git a/lib/generate-plugin/templates/src/cjs.js.tpl b/lib/generate-plugin/templates/src/cjs.js.tpl new file mode 100644 index 00000000000..82657ce3a74 --- /dev/null +++ b/lib/generate-plugin/templates/src/cjs.js.tpl @@ -0,0 +1 @@ +module.exports = require('./index').default; diff --git a/lib/generate-plugin/templates/test/fixtures/simple-file.js.tpl b/lib/generate-plugin/templates/test/fixtures/simple-file.js.tpl new file mode 100644 index 00000000000..908ed137dff --- /dev/null +++ b/lib/generate-plugin/templates/test/fixtures/simple-file.js.tpl @@ -0,0 +1,3 @@ +import foo from "./foo"; // eslint-disable-line + +console.log(foo); diff --git a/lib/generate-plugin/templates/test/functional.test.js.tpl b/lib/generate-plugin/templates/test/functional.test.js.tpl new file mode 100644 index 00000000000..07f2099cec0 --- /dev/null +++ b/lib/generate-plugin/templates/test/functional.test.js.tpl @@ -0,0 +1,10 @@ +import { + runWebpackExampleInMemory, +} from '../test/test-utils'; + +test('should run with no errors or warnings', async () => { + const buildStats = await runWebpackExampleInMemory('simple'); + const { errors, warnings } = buildStats; + + expect([...errors, ...warnings].length).toBe(0); +}); diff --git a/lib/generate-plugin/templates/test/test-utils.js.tpl b/lib/generate-plugin/templates/test/test-utils.js.tpl new file mode 100644 index 00000000000..bf8116f065f --- /dev/null +++ b/lib/generate-plugin/templates/test/test-utils.js.tpl @@ -0,0 +1,82 @@ +import path from 'path'; +import webpack from 'webpack'; +import Promise from 'bluebird'; +import MemoryFs from 'memory-fs'; + +const fs = new MemoryFs(); +const unitTestFixtures = path.resolve(__dirname, 'fixtures'); + +/** + * + * + * @param {string} fixtureName + * @param {string} [withQueryString=''] + * @returns {string} Absolute path of a file with query that is to be run by a loader. + */ +function getFixtureResource(fixtureName, withQueryString = '') { + return `${getFixture(fixtureName)}?${withQueryString}`; +} + +/** + * + * + * @param {string} fixtureName + * @returns {string} Absolute path of a file with query that is to be run by a loader. + */ +function getFixture(fixtureName) { + return path.resolve(unitTestFixtures, `${fixtureName}.js`); +} + +/** + * + * + * @param {Object} withOptions - Loader Options + * @returns {{loader: string, options: Object}} + */ +function getLoader(withOptions) { + return [{ loader: path.resolve(__dirname, '../dist/index.js'), options: withOptions }]; +} + +/** + * + * + * @param {string} exampleName + * @returns {Object|Array} - Returns an object or array of objects representing the webpack configuration options + */ +function getExampleConfig(exampleName) { + return require(`../examples/${exampleName}/webpack.config.js`); +} + +/** + * + * + * @param {string} exampleName - name of example inside of examples folder + * @returns + */ +async function runWebpackExampleInMemory(exampleName) { + const webpackConfig = getExampleConfig(exampleName); + const compiler = webpack(webpackConfig); + + compiler.outputFileSystem = fs; + + const run = Promise.promisify(compiler.run, { context: compiler }); + const stats = await run(); + + + const { compilation } = stats; + const { errors, warnings, assets, entrypoints, chunks, modules } = compilation; + const statsJson = stats.toJson(); + + return { + assets, + entrypoints, + errors, + warnings, + stats, + chunks, + modules, + statsJson, + }; +} + +export { getExampleConfig, runWebpackExampleInMemory, fs, getFixtureResource, getLoader, getFixture }; diff --git a/lib/utils/copy-utils.js b/lib/utils/copy-utils.js new file mode 100644 index 00000000000..e515d862257 --- /dev/null +++ b/lib/utils/copy-utils.js @@ -0,0 +1,50 @@ +var path = require("path"); + +/** + * Takes in a file path in the `./templates` directory. Copies that + * file to the destination, with the `.tpl` extension stripped. + * + * @param {Generator} generator A Yeoman Generator instance + * @param {string} templateDir Absolute path to template directory + * @returns {Function} A curried function that takes a file path and copies it + */ +var generatorCopy = (generator, templateDir) => /** @param {string} filePath */ (filePath) => { + var sourceParts = templateDir.split(path.delimiter); + sourceParts.push.apply(sourceParts, filePath.split("/")); + var targetParts = path.dirname(filePath).split("/"); + targetParts.push(path.basename(filePath, ".tpl")); + + generator.fs.copy( + path.join.apply(null, sourceParts), + generator.destinationPath(path.join.apply(null, targetParts)) + ); +}; + +/** + * Takes in a file path in the `./templates` directory. Copies that + * file to the destination, with the `.tpl` extension and `_` prefix + * stripped. Passes `this.props` to the template. + * + * @param {Generator} generator A Yeoman Generator instance + * @param {string} templateDir Absolute path to template directory + * @param {any} templateData An object containing the data passed to + * the template files. + * @returns {Function} A curried function that takes a file path and copies it + */ +var generatorCopyTpl = (generator, templateDir, templateData) => /** @param {string} filePath */ (filePath) => { + var sourceParts = templateDir.split(path.delimiter); + sourceParts.push.apply(sourceParts, filePath.split("/")); + var targetParts = path.dirname(filePath).split("/"); + targetParts.push(path.basename(filePath, ".tpl").slice(1)); + + generator.fs.copyTpl( + path.join.apply(null, sourceParts), + generator.destinationPath(path.join.apply(null, targetParts)), + templateData + ); +}; + +module.exports = { + generatorCopy, + generatorCopyTpl, +}; diff --git a/lib/utils/webpack-generator.js b/lib/utils/webpack-generator.js new file mode 100644 index 00000000000..f7f058098a6 --- /dev/null +++ b/lib/utils/webpack-generator.js @@ -0,0 +1,65 @@ +var path = require("path"); +var mkdirp = require("mkdirp"); +var Generator = require("yeoman-generator"); +var copyUtils = require("../utils/copy-utils"); + +/** + * Creates a Yeoman Generator that generates a project conforming + * to webpack-defaults. + * + * @param {any[]} prompts An array of Yeoman prompt objects + * + * @param {string} templateDir Absolute path to template directory + * + * @param {string[]} copyFiles An array of file paths (relative to `./templates`) + * of files to be copied to the generated project. File paths should be of the + * form `path/to/file.js.tpl`. + * + * @param {string[]} copyTemplateFiles An array of file paths (relative to + * `./templates`) of files to be copied to the generated project. Template + * file paths should be of the form `path/to/_file.js.tpl`. + * + * @param {Function} templateFn A function that is passed a generator instance and + * returns an object containing data to be supplied to the template files. + * + * @returns {Generator} A class extending Generator + */ +function webpackGenerator(prompts, templateDir, copyFiles, copyTemplateFiles, templateFn) { + //eslint-disable-next-line + return class extends Generator { + prompting() { + return this.prompt(prompts).then(props => { + this.props = props; + }); + } + + default() { + var currentDirName = path.basename(this.destinationPath()); + if (currentDirName !== this.props.name) { + this.log(` + Your project must be inside a folder named ${this.props.name} + I will create this folder for you. + `); + mkdirp(this.props.name); + var pathToProjectDir = this.destinationPath(this.props.name); + this.destinationRoot(pathToProjectDir); + } + } + + writing() { + this.copy = copyUtils.generatorCopy(this, templateDir); + this.copyTpl = copyUtils.generatorCopyTpl(this, templateDir, templateFn(this)); + + copyFiles.forEach(this.copy); + copyTemplateFiles.forEach(this.copyTpl); + } + + install() { + this.npmInstall(["webpack-defaults", "bluebird"], { "save-dev": true }).then(() => { + this.spawnCommand("npm", ["run", "webpack-defaults"]); + }); + } + }; +} + +module.exports = webpackGenerator; diff --git a/package-lock.json b/package-lock.json index 504137263c9..db75dc657e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1449,7 +1449,6 @@ "requires": { "anymatch": "1.3.0", "async-each": "1.0.1", - "fsevents": "1.1.2", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -5869,12 +5868,6 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, - "nan": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", - "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=", - "optional": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/package.json b/package.json index 3a99527065c..9c28c1776d4 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "listr": "^0.12.0", "loader-utils": "^1.1.0", "lodash": "^4.17.4", + "mkdirp": "^0.5.1", "p-each-series": "^1.0.0", "p-lazy": "^1.0.0", "prettier": "^1.5.3",