WIP - add extractor, generate snippet_data

This commit is contained in:
Stefan Fejes
2019-08-20 15:52:05 +02:00
parent 88084d3d30
commit cc8f1d8a7a
37396 changed files with 4588842 additions and 133 deletions

View File

@ -0,0 +1,35 @@
"use strict";
const path = require(`path`);
const fs = require(`fs-extra`);
const chokidar = require(`chokidar`);
exports.createPagesStatefully = async ({
store,
actions
}, options, done) => {
if (process.env.NODE_ENV !== `production`) {
const {
program
} = store.getState();
const {
createPage
} = actions;
const source = path.join(__dirname, `./raw_dev-404-page.js`);
const destination = path.join(program.directory, `.cache`, `dev-404-page.js`);
const copy = () => fs.copy(source, destination);
await copy();
createPage({
component: destination,
path: `/dev-404-page/`
});
chokidar.watch(source).on(`change`, () => copy()).on(`ready`, () => done());
} else {
done();
}
};
//# sourceMappingURL=gatsby-node.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/dev-404-page/gatsby-node.js"],"names":["path","require","fs","chokidar","exports","createPagesStatefully","store","actions","options","done","process","env","NODE_ENV","program","getState","createPage","source","join","__dirname","destination","directory","copy","component","watch","on"],"mappings":";;AAAA,MAAMA,IAAI,GAAGC,OAAO,CAAE,MAAF,CAApB;;AACA,MAAMC,EAAE,GAAGD,OAAO,CAAE,UAAF,CAAlB;;AACA,MAAME,QAAQ,GAAGF,OAAO,CAAE,UAAF,CAAxB;;AAEAG,OAAO,CAACC,qBAAR,GAAgC,OAAO;AAAEC,EAAAA,KAAF;AAASC,EAAAA;AAAT,CAAP,EAA2BC,OAA3B,EAAoCC,IAApC,KAA6C;AAC3E,MAAIC,OAAO,CAACC,GAAR,CAAYC,QAAZ,KAA0B,YAA9B,EAA2C;AACzC,UAAM;AAAEC,MAAAA;AAAF,QAAcP,KAAK,CAACQ,QAAN,EAApB;AACA,UAAM;AAAEC,MAAAA;AAAF,QAAiBR,OAAvB;AACA,UAAMS,MAAM,GAAGhB,IAAI,CAACiB,IAAL,CAAUC,SAAV,EAAsB,uBAAtB,CAAf;AACA,UAAMC,WAAW,GAAGnB,IAAI,CAACiB,IAAL,CAClBJ,OAAO,CAACO,SADU,EAEjB,QAFiB,EAGjB,iBAHiB,CAApB;;AAKA,UAAMC,IAAI,GAAG,MAAMnB,EAAE,CAACmB,IAAH,CAAQL,MAAR,EAAgBG,WAAhB,CAAnB;;AACA,UAAME,IAAI,EAAV;AACAN,IAAAA,UAAU,CAAC;AACTO,MAAAA,SAAS,EAAEH,WADF;AAETnB,MAAAA,IAAI,EAAG;AAFE,KAAD,CAAV;AAIAG,IAAAA,QAAQ,CACLoB,KADH,CACSP,MADT,EAEGQ,EAFH,CAEO,QAFP,EAEgB,MAAMH,IAAI,EAF1B,EAGGG,EAHH,CAGO,OAHP,EAGe,MAAMf,IAAI,EAHzB;AAID,GAnBD,MAmBO;AACLA,IAAAA,IAAI;AACL;AACF,CAvBD","sourcesContent":["const path = require(`path`)\nconst fs = require(`fs-extra`)\nconst chokidar = require(`chokidar`)\n\nexports.createPagesStatefully = async ({ store, actions }, options, done) => {\n if (process.env.NODE_ENV !== `production`) {\n const { program } = store.getState()\n const { createPage } = actions\n const source = path.join(__dirname, `./raw_dev-404-page.js`)\n const destination = path.join(\n program.directory,\n `.cache`,\n `dev-404-page.js`\n )\n const copy = () => fs.copy(source, destination)\n await copy()\n createPage({\n component: destination,\n path: `/dev-404-page/`,\n })\n chokidar\n .watch(source)\n .on(`change`, () => copy())\n .on(`ready`, () => done())\n } else {\n done()\n }\n}\n"],"file":"gatsby-node.js"}

View File

@ -0,0 +1,3 @@
// noop
"use strict";
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/dev-404-page/index.js"],"names":[],"mappings":"AAAA","sourcesContent":["// noop\n"],"file":"index.js"}

View File

@ -0,0 +1,11 @@
{
"name": "dev-404-page",
"version": "1.0.0",
"description": "Internal plugin to add a 404 page in development with helpful information",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"license": "MIT"
}

View File

@ -0,0 +1,147 @@
import React from "react"
import PropTypes from "prop-types"
import { graphql, Link } from "gatsby"
class Dev404Page extends React.Component {
static propTypes = {
data: PropTypes.object,
custom404: PropTypes.element,
location: PropTypes.object,
}
constructor(props) {
super(props)
const { data } = this.props
const pagePaths = data.allSitePage.nodes.map(node => node.path)
this.state = {
showCustom404: false,
initPagePaths: pagePaths,
pagePaths: pagePaths,
pagePathSearchTerms: ``,
}
this.showCustom404 = this.showCustom404.bind(this)
this.handlePagePathSearch = this.handlePagePathSearch.bind(this)
this.handleSearchTermChange = this.handleSearchTermChange.bind(this)
}
showCustom404() {
this.setState({ showCustom404: true })
}
handleSearchTermChange(event) {
this.setState({
pagePathSearchTerms: event.target.value,
})
}
handlePagePathSearch(event) {
event.preventDefault()
const tempPagePaths = [...this.state.initPagePaths]
const searchTerm = new RegExp(`${this.state.pagePathSearchTerms}`)
this.setState({
pagePaths: tempPagePaths.filter(pagePath => searchTerm.test(pagePath)),
})
}
render() {
const { pathname } = this.props.location
let newFilePath
if (pathname === `/`) {
newFilePath = `src/pages/index.js`
} else if (pathname.slice(-1) === `/`) {
newFilePath = `src/pages${pathname.slice(0, -1)}.js`
} else {
newFilePath = `src/pages${pathname}.js`
}
return this.state.showCustom404 ? (
this.props.custom404
) : (
<div>
<h1>Gatsby.js development 404 page</h1>
<p>
{`There's not a page yet at `}
<code>{pathname}</code>
</p>
{this.props.custom404 ? (
<p>
<button onClick={this.showCustom404}>
Preview custom 404 page
</button>
</p>
) : (
<p>
{`A custom 404 page wasn't detected - if you would like to add one, create a component in your site directory at `}
<code>src/pages/404.js</code>.
</p>
)}
<p>
Create a React.js component in your site directory at
{` `}
<code>{newFilePath}</code>
{` `}
and this page will automatically refresh to show the new page
component you created.
</p>
{this.state.initPagePaths.length > 0 && (
<div>
<p>
If you were trying to reach another page, perhaps you can find it
below.
</p>
<h2>
Pages (
{this.state.pagePaths.length != this.state.initPagePaths.length
? `${this.state.pagePaths.length}/${
this.state.initPagePaths.length
}`
: this.state.initPagePaths.length}
)
</h2>
<form onSubmit={this.handlePagePathSearch}>
<label>
Search:
<input
type="text"
id="search"
placeholder="Search pages..."
value={this.state.pageSearchTerm}
onChange={this.handleSearchTermChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
<ul>
{this.state.pagePaths.map(
(pagePath, index) =>
index < 100 && (
<li key={pagePath}>
<Link to={pagePath}>{pagePath}</Link>
</li>
)
)}
{this.state.pagePaths.length > 100 && (
<p style={{ fontWeight: `bold` }}>
... and {this.state.pagePaths.length - 100} more.
</p>
)}
</ul>
</div>
)}
</div>
)
}
}
export default Dev404Page
export const pagesQuery = graphql`
query PagesQuery {
allSitePage(filter: { path: { ne: "/dev-404-page/" } }) {
nodes {
path
}
}
}
`

View File

@ -0,0 +1,164 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
const moment = require(`moment`);
const chokidar = require(`chokidar`);
const systemPath = require(`path`);
const _ = require(`lodash`);
const {
emitter
} = require(`../../redux`);
const {
boundActionCreators
} = require(`../../redux/actions`);
const {
getNode
} = require(`../../db/nodes`);
function transformPackageJson(json) {
const transformDeps = deps => _.entries(deps).map(([name, version]) => {
return {
name,
version
};
});
json = _.pick(json, [`name`, `description`, `version`, `main`, `keywords`, `author`, `license`, `dependencies`, `devDependencies`, `peerDependencies`, `optionalDependecies`, `bundledDependecies`]);
json.dependencies = transformDeps(json.dependencies);
json.devDependencies = transformDeps(json.devDependencies);
json.peerDependencies = transformDeps(json.peerDependencies);
json.optionalDependecies = transformDeps(json.optionalDependecies);
json.bundledDependecies = transformDeps(json.bundledDependecies);
return json;
}
const createPageId = path => `SitePage ${path}`;
exports.sourceNodes = ({
createContentDigest,
actions,
store
}) => {
const {
createNode
} = actions;
const state = store.getState();
const {
program
} = state;
const {
flattenedPlugins
} = state; // Add our default development page since we know it's going to
// exist and we need a node to exist so its query works :-)
const page = {
path: `/dev-404-page/`
};
createNode(Object.assign({}, page, {
id: createPageId(page.path),
parent: null,
children: [],
internal: {
type: `SitePage`,
contentDigest: createContentDigest(page)
}
}));
flattenedPlugins.forEach(plugin => {
plugin.pluginFilepath = plugin.resolve;
createNode(Object.assign({}, plugin, {
packageJson: transformPackageJson(require(`${plugin.resolve}/package.json`)),
parent: null,
children: [],
internal: {
contentDigest: createContentDigest(plugin),
type: `SitePlugin`
}
}));
}); // Add site node.
const buildTime = moment().subtract(process.uptime(), `seconds`).toJSON();
const createGatsbyConfigNode = (config = {}) => {
// Delete plugins from the config as we add plugins above.
const configCopy = Object.assign({}, config);
delete configCopy.plugins;
const node = Object.assign({
siteMetadata: Object.assign({}, configCopy.siteMetadata),
port: state.program.port,
host: state.program.host
}, configCopy, {
buildTime
});
createNode(Object.assign({}, node, {
id: `Site`,
parent: null,
children: [],
internal: {
contentDigest: createContentDigest(node),
type: `Site`
}
}));
};
createGatsbyConfigNode(state.config);
const pathToGatsbyConfig = systemPath.join(program.directory, `gatsby-config.js`);
chokidar.watch(pathToGatsbyConfig).on(`change`, () => {
const oldCache = require.cache[require.resolve(pathToGatsbyConfig)];
try {
// Delete require cache so we can reload the module.
delete require.cache[require.resolve(pathToGatsbyConfig)];
const config = require(pathToGatsbyConfig);
createGatsbyConfigNode(config);
} catch (e) {
// Restore the old cache since requiring the new gatsby-config.js failed.
if (oldCache !== undefined) {
require.cache[require.resolve(pathToGatsbyConfig)] = oldCache;
}
}
});
};
exports.onCreatePage = ({
createContentDigest,
page,
actions
}) => {
const {
createNode
} = actions; // eslint-disable-next-line
const pageWithoutUpdated = (0, _objectWithoutPropertiesLoose2.default)(page, ["updatedAt"]); // Add page.
createNode(Object.assign({}, pageWithoutUpdated, {
id: createPageId(page.path),
parent: null,
children: [],
internal: {
type: `SitePage`,
contentDigest: createContentDigest(pageWithoutUpdated),
description: page.pluginCreatorId === `Plugin default-site-plugin` ? `Your site's "gatsby-node.js"` : page.pluginCreatorId
}
}));
}; // Listen for DELETE_PAGE and delete page nodes.
emitter.on(`DELETE_PAGE`, action => {
const nodeId = createPageId(action.payload.path);
const node = getNode(nodeId);
boundActionCreators.deleteNode({
node
});
});
//# sourceMappingURL=gatsby-node.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
// noop
"use strict";
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/internal-data-bridge/index.js"],"names":[],"mappings":"AAAA","sourcesContent":["// noop\n"],"file":"index.js"}

View File

@ -0,0 +1,11 @@
{
"name": "internal-data-bridge",
"version": "1.0.0",
"description": "An internal Gatsby plugin which creates data nodes from internal data",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"license": "MIT"
}

View File

@ -0,0 +1,36 @@
"use strict";
const fs = require(`fs-extra`);
const apiRunnerNode = require(`../../utils/api-runner-node`);
const {
withBasePath
} = require(`../../utils/path`);
exports.onPreBootstrap = async ({
store
}) => {
const {
directory,
browserslist
} = store.getState().program;
const directoryPath = withBasePath(directory);
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `develop`
});
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `develop-html`
});
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `build-javascript`
});
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `build-html`
});
const babelState = JSON.stringify(Object.assign({}, store.getState().babelrc, {
browserslist
}), null, 2);
await fs.writeFile(directoryPath(`.cache/babelState.json`), babelState);
};
//# sourceMappingURL=gatsby-node.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/load-babel-config/gatsby-node.js"],"names":["fs","require","apiRunnerNode","withBasePath","exports","onPreBootstrap","store","directory","browserslist","getState","program","directoryPath","stage","babelState","JSON","stringify","babelrc","writeFile"],"mappings":";;AAEA,MAAMA,EAAE,GAAGC,OAAO,CAAE,UAAF,CAAlB;;AAEA,MAAMC,aAAa,GAAGD,OAAO,CAAE,6BAAF,CAA7B;;AACA,MAAM;AAAEE,EAAAA;AAAF,IAAmBF,OAAO,CAAE,kBAAF,CAAhC;;AAEAG,OAAO,CAACC,cAAR,GAAyB,OAAO;AAAEC,EAAAA;AAAF,CAAP,KAAqB;AAC5C,QAAM;AAAEC,IAAAA,SAAF;AAAaC,IAAAA;AAAb,MAA8BF,KAAK,CAACG,QAAN,GAAiBC,OAArD;AACA,QAAMC,aAAa,GAAGR,YAAY,CAACI,SAAD,CAAlC;AAEA,QAAML,aAAa,CAAE,qBAAF,EAAwB;AACzCU,IAAAA,KAAK,EAAG;AADiC,GAAxB,CAAnB;AAGA,QAAMV,aAAa,CAAE,qBAAF,EAAwB;AACzCU,IAAAA,KAAK,EAAG;AADiC,GAAxB,CAAnB;AAGA,QAAMV,aAAa,CAAE,qBAAF,EAAwB;AACzCU,IAAAA,KAAK,EAAG;AADiC,GAAxB,CAAnB;AAGA,QAAMV,aAAa,CAAE,qBAAF,EAAwB;AACzCU,IAAAA,KAAK,EAAG;AADiC,GAAxB,CAAnB;AAIA,QAAMC,UAAU,GAAGC,IAAI,CAACC,SAAL,mBAEZT,KAAK,CAACG,QAAN,GAAiBO,OAFL;AAGfR,IAAAA;AAHe,MAKjB,IALiB,EAMjB,CANiB,CAAnB;AASA,QAAMR,EAAE,CAACiB,SAAH,CAAaN,aAAa,CAAE,wBAAF,CAA1B,EAAsDE,UAAtD,CAAN;AACD,CA3BD","sourcesContent":["/* @flow */\n\nconst fs = require(`fs-extra`)\n\nconst apiRunnerNode = require(`../../utils/api-runner-node`)\nconst { withBasePath } = require(`../../utils/path`)\n\nexports.onPreBootstrap = async ({ store }) => {\n const { directory, browserslist } = store.getState().program\n const directoryPath = withBasePath(directory)\n\n await apiRunnerNode(`onCreateBabelConfig`, {\n stage: `develop`,\n })\n await apiRunnerNode(`onCreateBabelConfig`, {\n stage: `develop-html`,\n })\n await apiRunnerNode(`onCreateBabelConfig`, {\n stage: `build-javascript`,\n })\n await apiRunnerNode(`onCreateBabelConfig`, {\n stage: `build-html`,\n })\n\n const babelState = JSON.stringify(\n {\n ...store.getState().babelrc,\n browserslist,\n },\n null,\n 2\n )\n\n await fs.writeFile(directoryPath(`.cache/babelState.json`), babelState)\n}\n"],"file":"gatsby-node.js"}

View File

@ -0,0 +1,3 @@
// noop
"use strict";
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/load-babel-config/index.js"],"names":[],"mappings":"AAAA","sourcesContent":["// noop\n"],"file":"index.js"}

View File

@ -0,0 +1,11 @@
{
"name": "load-babel-config",
"version": "1.0.0",
"description": "Internal plugin that handles loading Babel configs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"license": "MIT"
}

View File

@ -0,0 +1,20 @@
"use strict";
let created404 = false;
exports.onCreatePage = ({
page,
store,
actions
}) => {
// Copy /404/ to /404.html as many static site hosts expect
// site 404 pages to be named this.
// https://www.gatsbyjs.org/docs/add-404-page/
if (!created404 && /^\/?404\/?$/.test(page.path)) {
actions.createPage(Object.assign({}, page, {
path: `/404.html`
}));
created404 = true;
}
};
//# sourceMappingURL=gatsby-node.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/prod-404/gatsby-node.js"],"names":["created404","exports","onCreatePage","page","store","actions","test","path","createPage"],"mappings":";;AAAA,IAAIA,UAAU,GAAG,KAAjB;;AACAC,OAAO,CAACC,YAAR,GAAuB,CAAC;AAAEC,EAAAA,IAAF;AAAQC,EAAAA,KAAR;AAAeC,EAAAA;AAAf,CAAD,KAA8B;AACnD;AACA;AACA;AACA,MAAI,CAACL,UAAD,IAAe,cAAcM,IAAd,CAAmBH,IAAI,CAACI,IAAxB,CAAnB,EAAkD;AAChDF,IAAAA,OAAO,CAACG,UAAR,mBACKL,IADL;AAEEI,MAAAA,IAAI,EAAG;AAFT;AAIAP,IAAAA,UAAU,GAAG,IAAb;AACD;AACF,CAXD","sourcesContent":["let created404 = false\nexports.onCreatePage = ({ page, store, actions }) => {\n // Copy /404/ to /404.html as many static site hosts expect\n // site 404 pages to be named this.\n // https://www.gatsbyjs.org/docs/add-404-page/\n if (!created404 && /^\\/?404\\/?$/.test(page.path)) {\n actions.createPage({\n ...page,\n path: `/404.html`,\n })\n created404 = true\n }\n}\n"],"file":"gatsby-node.js"}

View File

@ -0,0 +1,3 @@
// noop
"use strict";
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/prod-404/index.js"],"names":[],"mappings":"AAAA","sourcesContent":["// noop\n"],"file":"index.js"}

View File

@ -0,0 +1,11 @@
{
"name": "prod-404",
"version": "1.0.0",
"description": "Internal plugin to detect various flavors of 404 pages and ensure there's a 404.html path created as well to ensure compatibility with static hosts",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"license": "MIT"
}

View File

@ -0,0 +1,30 @@
"use strict";
const GatsbyThemeComponentShadowingResolverPlugin = require(`.`);
exports.onCreateWebpackConfig = ({
store,
stage,
getConfig,
rules,
loaders,
actions
}, pluginOptions) => {
const {
themes,
flattenedPlugins
} = store.getState();
actions.setWebpackConfig({
resolve: {
plugins: [new GatsbyThemeComponentShadowingResolverPlugin({
themes: themes.themes ? themes.themes : flattenedPlugins.map(plugin => {
return {
themeDir: plugin.pluginFilepath,
themeName: plugin.name
};
})
})]
}
});
};
//# sourceMappingURL=gatsby-node.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../../../src/internal-plugins/webpack-theme-component-shadowing/gatsby-node.js"],"names":["GatsbyThemeComponentShadowingResolverPlugin","require","exports","onCreateWebpackConfig","store","stage","getConfig","rules","loaders","actions","pluginOptions","themes","flattenedPlugins","getState","setWebpackConfig","resolve","plugins","map","plugin","themeDir","pluginFilepath","themeName","name"],"mappings":";;AAAA,MAAMA,2CAA2C,GAAGC,OAAO,CAAE,GAAF,CAA3D;;AAEAC,OAAO,CAACC,qBAAR,GAAgC,CAC9B;AAAEC,EAAAA,KAAF;AAASC,EAAAA,KAAT;AAAgBC,EAAAA,SAAhB;AAA2BC,EAAAA,KAA3B;AAAkCC,EAAAA,OAAlC;AAA2CC,EAAAA;AAA3C,CAD8B,EAE9BC,aAF8B,KAG3B;AACH,QAAM;AAAEC,IAAAA,MAAF;AAAUC,IAAAA;AAAV,MAA+BR,KAAK,CAACS,QAAN,EAArC;AAEAJ,EAAAA,OAAO,CAACK,gBAAR,CAAyB;AACvBC,IAAAA,OAAO,EAAE;AACPC,MAAAA,OAAO,EAAE,CACP,IAAIhB,2CAAJ,CAAgD;AAC9CW,QAAAA,MAAM,EAAEA,MAAM,CAACA,MAAP,GACJA,MAAM,CAACA,MADH,GAEJC,gBAAgB,CAACK,GAAjB,CAAqBC,MAAM,IAAI;AAC7B,iBAAO;AACLC,YAAAA,QAAQ,EAAED,MAAM,CAACE,cADZ;AAELC,YAAAA,SAAS,EAAEH,MAAM,CAACI;AAFb,WAAP;AAID,SALD;AAH0C,OAAhD,CADO;AADF;AADc,GAAzB;AAgBD,CAtBD","sourcesContent":["const GatsbyThemeComponentShadowingResolverPlugin = require(`.`)\n\nexports.onCreateWebpackConfig = (\n { store, stage, getConfig, rules, loaders, actions },\n pluginOptions\n) => {\n const { themes, flattenedPlugins } = store.getState()\n\n actions.setWebpackConfig({\n resolve: {\n plugins: [\n new GatsbyThemeComponentShadowingResolverPlugin({\n themes: themes.themes\n ? themes.themes\n : flattenedPlugins.map(plugin => {\n return {\n themeDir: plugin.pluginFilepath,\n themeName: plugin.name,\n }\n }),\n }),\n ],\n },\n })\n}\n"],"file":"gatsby-node.js"}

View File

@ -0,0 +1,175 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
const path = require(`path`);
const debug = require(`debug`)(`gatsby:component-shadowing`);
const fs = require(`fs`);
const _ = require(`lodash`);
const pathWithoutExtension = fullPath => {
const parsed = path.parse(fullPath);
return path.join(parsed.dir, parsed.name);
};
module.exports = class GatsbyThemeComponentShadowingResolverPlugin {
constructor({
projectRoot,
themes
}) {
(0, _defineProperty2.default)(this, "cache", {});
debug(`themes list`, themes.map(({
themeName
}) => themeName));
this.themes = themes;
this.projectRoot = projectRoot;
}
apply(resolver) {
resolver.hooks.relative.tapAsync(`GatsbyThemeComponentShadowingResolverPlugin`, (request, stack, callback) => {
const matchingThemes = this.getMatchingThemesForPath(request.path); // 0 matching themes happens a lot for paths we don't want to handle
// > 1 matching theme means we have a path like
// `gatsby-theme-blog/src/components/gatsby-theme-something/src/components`
if (matchingThemes.length > 1) {
throw new Error(`Gatsby can't differentiate between themes ${matchingThemes.map(theme => theme.themeName).join(` and `)} for path ${request.path}`);
}
if (matchingThemes.length !== 1) {
return callback();
} // theme is the theme package from which we're requiring the relative component
const [theme] = matchingThemes; // get the location of the component relative to src/
const [, component] = request.path.split(path.join(theme.themeDir, `src`));
if (
/**
* if someone adds
* ```
* modules: [path.resolve(__dirname, 'src'), 'node_modules'],
* ```
* to the webpack config, `issuer` is `null`, so we skip this check.
* note that it's probably a bad idea in general to set `modules`
* like this in a theme, but we also shouldn't artificially break
* people that do.
*/
request.context.issuer &&
/**
* An issuer is the file making the require request. It can
* be in a user's site or a theme. If the issuer is requesting
* a path in the shadow chain that it participates in, then we
* will let the request through as normal. Otherwise, we
* engage the shadowing algorithm.
*/
this.requestPathIsIssuerShadowPath({
requestPath: request.path,
issuerPath: request.context.issuer,
userSiteDir: path.resolve(`.`)
})) {
return resolver.doResolve(resolver.hooks.describedRelative, request, null, {}, callback);
} // This is the shadowing algorithm.
const builtComponentPath = this.resolveComponentPath({
matchingTheme: theme.themeName,
themes: this.themes,
component
});
return resolver.doResolve(resolver.hooks.describedRelative, Object.assign({}, request, {
path: builtComponentPath || request.path
}), null, {}, callback);
});
} // check the cache, the user's project, and finally the theme files
resolveComponentPath({
matchingTheme: theme,
themes: ogThemes,
component
}) {
// don't include matching theme in possible shadowing paths
const themes = ogThemes.filter(({
themeName
}) => themeName !== theme);
if (!this.cache[`${theme}-${component}`]) {
this.cache[`${theme}-${component}`] = [path.join(path.resolve(`.`), `src`, theme)].concat(Array.from(themes).reverse().map(({
themeDir
}) => path.join(themeDir, `src`, theme))).map(dir => path.join(dir, component)).find(possibleComponentPath => {
debug(`possibleComponentPath`, possibleComponentPath);
let dir;
try {
// we use fs/path instead of require.resolve to work with
// TypeScript and alternate syntaxes
dir = fs.readdirSync(path.dirname(possibleComponentPath));
} catch (e) {
return false;
}
const exists = dir.map(filepath => {
const ext = path.extname(filepath);
const filenameWithoutExtension = path.basename(filepath, ext);
return filenameWithoutExtension;
}).includes(path.basename(possibleComponentPath, path.extname(possibleComponentPath)));
return exists;
});
}
return this.cache[`${theme}-${component}`];
}
getMatchingThemesForPath(filepath) {
// find out which theme's src/components dir we're requiring from
const allMatchingThemes = this.themes.filter(({
themeDir
}) => filepath.includes(path.join(themeDir, `src`))); // The same theme can be included twice in the themes list causing multiple
// matches. This case should only be counted as a single match for that theme.
return _.uniqBy(allMatchingThemes, `themeName`);
} // given a theme name, return all of the possible shadow locations
getBaseShadowDirsForThemes(theme) {
return Array.from(this.themes).reverse().map(({
themeName,
themeDir
}) => {
if (themeName === theme) {
return path.join(themeDir, `src`);
} else {
return path.join(themeDir, `src`, theme);
}
});
}
requestPathIsIssuerShadowPath({
requestPath,
issuerPath,
userSiteDir
}) {
// get the issuer's theme
const matchingThemes = this.getMatchingThemesForPath(requestPath);
if (matchingThemes.length !== 1) {
return false;
}
const [theme] = matchingThemes; // get the location of the component relative to src/
const [, component] = requestPath.split(path.join(theme.themeDir, `src`)); // get list of potential shadow locations
const shadowFiles = this.getBaseShadowDirsForThemes(theme.themeName).concat(path.join(userSiteDir, `src`, theme.themeName)).map(dir => path.join(dir, component)); // if the issuer is requesting a path that is a potential shadow path of itself
return shadowFiles.includes(pathWithoutExtension(issuerPath));
}
};
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,11 @@
{
"name": "webpack-theme-component-shadowing",
"version": "1.0.0",
"description": "An internal Gatsby plugin which handles configuring webpack to ensure theme components fall back from the user's site to theme modules.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Chris Biscardi <chris@christopherbiscardi.com>",
"license": "MIT"
}