diff --git a/packages/gatsby-cli/package.json b/packages/gatsby-cli/package.json index f955444270293..33beaeed664f3 100644 --- a/packages/gatsby-cli/package.json +++ b/packages/gatsby-cli/package.json @@ -25,6 +25,7 @@ "opentracing": "^0.14.3", "pretty-error": "^2.1.1", "resolve-cwd": "^2.0.0", + "semver": "^5.6.0", "source-map": "^0.5.7", "stack-trace": "^0.0.10", "update-notifier": "^2.3.0", diff --git a/packages/gatsby-cli/src/create-cli.js b/packages/gatsby-cli/src/create-cli.js index 1d9fbc654a38e..c06ccbe8656ba 100644 --- a/packages/gatsby-cli/src/create-cli.js +++ b/packages/gatsby-cli/src/create-cli.js @@ -298,10 +298,16 @@ module.exports = (argv, handlers) => { .command({ command: `new [rootPath] [starter]`, desc: `Create new Gatsby project.`, + builder: _ => + _.option(`use-pnp`, { + default: false, + type: `boolean`, + describe: `Turn on to use Yarn Plug'n'Play`, + }), handler: handlerP( - ({ rootPath, starter = `gatsbyjs/gatsby-starter-default` }) => { + ({ rootPath, starter = `gatsbyjs/gatsby-starter-default`, usePnp }) => { const initStarter = require(`./init-starter`) - return initStarter(starter, { rootPath }) + return initStarter(starter, { rootPath, usePnp }) } ), }) diff --git a/packages/gatsby-cli/src/init-starter.js b/packages/gatsby-cli/src/init-starter.js index 285d736b71dc6..45c500a7cde81 100644 --- a/packages/gatsby-cli/src/init-starter.js +++ b/packages/gatsby-cli/src/init-starter.js @@ -7,6 +7,7 @@ const sysPath = require(`path`) const report = require(`./reporter`) const url = require(`url`) const existsSync = require(`fs-exists-cached`).sync +const semver = require(`semver`) const spawn = (cmd: string) => { const [file, ...args] = cmd.split(/\s+/) @@ -27,15 +28,56 @@ const shouldUseYarn = () => { } } +const checkYarnVersion = () => { + let hasMinYarnPnp = false + let yarnVersion = null + try { + yarnVersion = execSync(`yarnpkg --version`) + .toString() + .trim() + hasMinYarnPnp = semver.gte(yarnVersion, `1.12.0`) + } catch (err) { + // ignore + } + return { + hasMinYarnPnp: hasMinYarnPnp, + yarnVersion: yarnVersion, + } +} + // Executes `npm install` or `yarn install` in rootPath. -const install = async rootPath => { +const install = async ({ rootPath, usePnp }: Options) => { const prevDir = process.cwd() report.info(`Installing packages...`) process.chdir(rootPath) try { - let cmd = shouldUseYarn() ? spawn(`yarnpkg`) : spawn(`npm install`) + let cmd + if (shouldUseYarn()) { + const yarnInfo = checkYarnVersion() + const args = [] + if (usePnp) { + if (!yarnInfo.hasMinYarnPnp) { + if (yarnInfo.yarnVersion) { + report.warn( + `You are using Yarn ${ + yarnInfo.yarnVersion + } together with the --use-pnp flag, but Plug'n'Play is only supported starting from the 1.12 release.\n\n` + + `Please update to Yarn 1.12 or higher for a better, fully supported experience.\n` + ) + } + // 1.11 had an issue with webpack-dev-middleware, so better not use PnP with it (never reached stable, but still) + } else { + args.push(`--enable-pnp`) + } + } + + cmd = execa(`yarnpkg`, args, { stdio: `inherit` }) + } else { + cmd = spawn(`npm install`) + } + await cmd } finally { process.chdir(prevDir) @@ -44,8 +86,13 @@ const install = async rootPath => { const ignored = path => !/^\.(git|hg)$/.test(sysPath.basename(path)) +type Options = { + rootPath: string, + usePnp: boolean, +} + // Copy starter from file system. -const copy = async (starterPath: string, rootPath: string) => { +const copy = async (starterPath: string, { rootPath, usePnp }: Options) => { // Chmod with 755. // 493 = parseInt('755', 8) await fs.mkdirp(rootPath, { mode: 493 }) @@ -71,13 +118,13 @@ const copy = async (starterPath: string, rootPath: string) => { report.success(`Created starter directory layout`) - await install(rootPath) + await install({ rootPath, usePnp }) return true } // Clones starter from URI. -const clone = async (hostInfo: any, rootPath: string) => { +const clone = async (hostInfo: any, { rootPath, usePnp }: Options) => { let url // Let people use private repos accessed over SSH. if (hostInfo.getDefaultRepresentation() === `sshurl`) { @@ -97,11 +144,12 @@ const clone = async (hostInfo: any, rootPath: string) => { await fs.remove(sysPath.join(rootPath, `.git`)) - await install(rootPath) + await install({ rootPath, usePnp }) } type InitOptions = { rootPath?: string, + usePnp?: boolean, } /** @@ -109,6 +157,7 @@ type InitOptions = { */ module.exports = async (starter: string, options: InitOptions = {}) => { const rootPath = options.rootPath || process.cwd() + const usePnp = options.usePnp || false const urlObject = url.parse(rootPath) if (urlObject.protocol && urlObject.host) { @@ -124,6 +173,6 @@ module.exports = async (starter: string, options: InitOptions = {}) => { } const hostedInfo = hostedGitInfo.fromUrl(starter) - if (hostedInfo) await clone(hostedInfo, rootPath) - else await copy(starter, rootPath) + if (hostedInfo) await clone(hostedInfo, { rootPath, usePnp }) + else await copy(starter, { rootPath, usePnp }) } diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index a759d7c2b3116..215282f7c8479 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -17,6 +17,7 @@ "@babel/runtime": "^7.0.0", "@babel/traverse": "^7.0.0", "@reach/router": "^1.1.1", + "address": "^1.0.3", "autoprefixer": "^8.6.5", "babel-core": "7.0.0-bridge.0", "babel-eslint": "^8.2.2", @@ -25,6 +26,7 @@ "babel-plugin-dynamic-import-node": "^1.2.0", "babel-plugin-remove-graphql-queries": "^2.5.1", "babel-preset-gatsby": "^0.1.3", + "babel-traverse": "^6.26.0", "better-queue": "^3.8.6", "bluebird": "^3.5.0", "cache-manager": "^2.9.0", @@ -57,6 +59,7 @@ "file-loader": "^1.1.11", "flat": "^4.0.0", "friendly-errors-webpack-plugin": "^1.6.1", + "fs-exists-cached": "^1.0.0", "fs-extra": "^5.0.0", "gatsby-cli": "^2.4.5", "gatsby-link": "^2.0.6", @@ -93,6 +96,7 @@ "optimize-css-assets-webpack-plugin": "^5.0.1", "parse-filepath": "^1.0.1", "physical-cpu-count": "^2.0.0", + "pnp-webpack-plugin": "^1.2.0", "postcss-flexbugs-fixes": "^3.0.0", "postcss-loader": "^2.1.3", "raw-loader": "^0.5.1", diff --git a/packages/gatsby/src/utils/webpack.config.js b/packages/gatsby/src/utils/webpack.config.js index 6e6d60f7de3fa..968ddda1190d9 100644 --- a/packages/gatsby/src/utils/webpack.config.js +++ b/packages/gatsby/src/utils/webpack.config.js @@ -4,6 +4,7 @@ const fs = require(`fs-extra`) const path = require(`path`) const dotenv = require(`dotenv`) const FriendlyErrorsWebpackPlugin = require(`friendly-errors-webpack-plugin`) +const PnpWebpackPlugin = require(`pnp-webpack-plugin`) const { store } = require(`../redux`) const { actions } = require(`../redux/actions`) const debug = require(`debug`)(`gatsby:webpack-config`) @@ -350,6 +351,11 @@ module.exports = async ( function getResolve() { const { program } = store.getState() return { + plugins: [ + // Adds support for installing with Plug'n'Play, leading to faster installs and adding + // guards against forgotten dependencies and such. + PnpWebpackPlugin, + ], // Use the program's extension list (generated via the // 'resolvableExtensions' API hook). extensions: [...program.extensions], @@ -392,6 +398,11 @@ module.exports = async ( } return { + plugins: [ + // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders + // from the current package. + PnpWebpackPlugin.moduleLoader(module), + ], modules: [...root, path.join(__dirname, `../loaders`), `node_modules`], } } diff --git a/packages/graphql-skip-limit/package.json b/packages/graphql-skip-limit/package.json index e467ca056bff2..73193aca66e28 100644 --- a/packages/graphql-skip-limit/package.json +++ b/packages/graphql-skip-limit/package.json @@ -16,6 +16,9 @@ "cross-env": "^5.1.4", "graphql": "^0.13.2" }, + "peerDependencies": { + "graphql": "^0.13.2" + }, "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/graphql-skip-limit#readme", "keywords": [ "gatsby", diff --git a/yarn.lock b/yarn.lock index 3404d92419ea6..cb12e69bb7327 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1991,7 +1991,7 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -address@1.0.3, address@^1.0.1: +address@1.0.3, address@^1.0.1, address@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/address/-/address-1.0.3.tgz#b5f50631f8d6cec8bd20c963963afb55e06cbce9" integrity sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg== @@ -14665,6 +14665,13 @@ pngquant-bin@^5.0.0: execa "^0.10.0" logalot "^2.0.0" +pnp-webpack-plugin@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.2.0.tgz#a85338bc313b8a0469c1d8c5c5d016873be47cb2" + integrity sha512-cCaqL7SZCqeJoCEL5GhSGU9CFJOMcDIEAS83X+0m2q25vtt9IqrMJ5dObm8WyqnM4CHRaIn0VVkn7RXdZ0C6Kg== + dependencies: + ts-pnp "^1.0.0" + portfinder@^1.0.9: version "1.0.17" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.17.tgz#a8a1691143e46c4735edefcf4fbcccedad26456a" @@ -16882,6 +16889,11 @@ semver@^4.0.3: resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= +semver@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -18659,6 +18671,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.3.tgz#e29bd1614c6458d44869fc28b255ab7857ef7c24" integrity sha512-fwkLWH+DimvA4YCy+/nvJd61nWQQ2liO/nF/RjkTpiOGi+zxZzVkhb1mvbHIIW4b/8nDsYI8uTmAlc0nNkRMOw== +ts-pnp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.0.0.tgz#44a3a9e8c13fcb711bcda75d7b576c21af120c9d" + integrity sha512-qgwM7eBrxFvZSXLtSvjf3c2mXwJOOGD49VlE+KocUGX95DuMdLc/psZHBnPpZL5b2NU7VtQGHRCWF3cNfe5kxQ== + tsickle@^0.27.2: version "0.27.5" resolved "https://registry.yarnpkg.com/tsickle/-/tsickle-0.27.5.tgz#41e1a41a5acf971cbb2b0558a9590779234d591f"