-
Notifications
You must be signed in to change notification settings - Fork 10.3k
fix(gatsby-plugin-netlify-cms): exclude node_modules from cms #15191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,23 @@ | ||
import path from "path" | ||
import { get, mapValues, isPlainObject, trim } from "lodash" | ||
import { mapValues, isPlainObject, trim } from "lodash" | ||
import webpack from "webpack" | ||
import HtmlWebpackPlugin from "html-webpack-plugin" | ||
import HtmlWebpackExcludeAssetsPlugin from "html-webpack-exclude-assets-plugin" | ||
import MiniCssExtractPlugin from "mini-css-extract-plugin" | ||
// TODO: swap back when https://github.com/geowarin/friendly-errors-webpack-plugin/pull/86 lands | ||
import FriendlyErrorsPlugin from "@pieh/friendly-errors-webpack-plugin" | ||
|
||
/** | ||
* Deep mapping function for plain objects and arrays. Allows any value, | ||
* including an object or array, to be transformed. | ||
*/ | ||
// Deep mapping function for plain objects and arrays. Allows any value, | ||
// including an object or array, to be transformed. | ||
function deepMap(obj, fn) { | ||
/** | ||
* If the transform function transforms the value, regardless of type, | ||
* return the transformed value. | ||
*/ | ||
// If the transform function transforms the value, regardless of type, return | ||
// the transformed value. | ||
const mapped = fn(obj) | ||
if (mapped !== obj) { | ||
return mapped | ||
} | ||
|
||
/** | ||
* Recursively deep map arrays and plain objects, otherwise return the value. | ||
*/ | ||
// Recursively deep map arrays and plain objects, otherwise return the value. | ||
if (Array.isArray(obj)) { | ||
return obj.map(value => deepMap(value, fn)) | ||
} | ||
|
@@ -33,6 +27,42 @@ function deepMap(obj, fn) { | |
return obj | ||
} | ||
|
||
function replaceRule(value) { | ||
// If `value` does not have a `test` property, it isn't a rule object. | ||
if (!value || !value.test) { | ||
return value | ||
} | ||
|
||
// when javascript we exclude node_modules | ||
if ( | ||
value.type === `javascript/auto` && | ||
value.exclude && | ||
value.exclude instanceof RegExp | ||
) { | ||
return { | ||
...value, | ||
exclude: new RegExp( | ||
[value.exclude.source, `node_modules|bower_components`].join(`|`) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't know for sure that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm checking that it's a regex now. If people have a custom js rule they should make sure to exclude node_modules themselves. |
||
), | ||
} | ||
} | ||
|
||
// Manually swap `style-loader` for `MiniCssExtractPlugin.loader`. | ||
// `style-loader` is only used in development, and doesn't allow us to pass | ||
// the `styles` entry css path to Netlify CMS. | ||
if ( | ||
typeof value.loader === `string` && | ||
value.loader.includes(`style-loader`) | ||
) { | ||
return { | ||
...value, | ||
loader: MiniCssExtractPlugin.loader, | ||
} | ||
} | ||
|
||
return value | ||
} | ||
|
||
exports.onCreateDevServer = ({ app, store }, { publicPath = `admin` }) => { | ||
const { program } = store.getState() | ||
const publicPathClean = trim(publicPath, `/`) | ||
|
@@ -49,7 +79,7 @@ exports.onCreateDevServer = ({ app, store }, { publicPath = `admin` }) => { | |
} | ||
|
||
exports.onCreateWebpackConfig = ( | ||
{ store, stage, getConfig, plugins, pathPrefix }, | ||
{ store, stage, getConfig, plugins, pathPrefix, loaders }, | ||
{ | ||
modulePath, | ||
publicPath = `admin`, | ||
|
@@ -79,26 +109,11 @@ exports.onCreateWebpackConfig = ( | |
path: path.join(program.directory, `public`, publicPathClean), | ||
}, | ||
module: { | ||
/** | ||
* Manually swap `style-loader` for `MiniCssExtractPlugin.loader`. | ||
* `style-loader` is only used in development, and doesn't allow us to | ||
* pass the `styles` entry css path to Netlify CMS. | ||
*/ | ||
rules: deepMap(gatsbyConfig.module.rules, value => { | ||
if ( | ||
typeof get(value, `loader`) === `string` && | ||
value.loader.includes(`style-loader`) | ||
) { | ||
return { ...value, loader: MiniCssExtractPlugin.loader } | ||
} | ||
return value | ||
}), | ||
rules: deepMap(gatsbyConfig.module.rules, replaceRule), | ||
}, | ||
plugins: [ | ||
/** | ||
* Remove plugins that either attempt to process the core Netlify CMS | ||
* application, or that we want to replace with our own instance. | ||
*/ | ||
// Remove plugins that either attempt to process the core Netlify CMS | ||
// application, or that we want to replace with our own instance. | ||
...gatsbyConfig.plugins.filter( | ||
plugin => | ||
![`MiniCssExtractPlugin`, `GatsbyWebpackStatsExtractor`].find( | ||
|
@@ -122,49 +137,37 @@ exports.onCreateWebpackConfig = ( | |
}, | ||
}), | ||
|
||
/** | ||
* Use a simple filename with no hash so we can access from source by | ||
* path. | ||
*/ | ||
// Use a simple filename with no hash so we can access from source by | ||
// path. | ||
new MiniCssExtractPlugin({ | ||
filename: `[name].css`, | ||
}), | ||
|
||
/** | ||
* Auto generate CMS index.html page. | ||
*/ | ||
// Auto generate CMS index.html page. | ||
new HtmlWebpackPlugin({ | ||
title: htmlTitle, | ||
chunks: [`cms`], | ||
excludeAssets: [/cms.css/], | ||
}), | ||
|
||
/** | ||
* Exclude CSS from index.html, as any imported styles are assumed to be | ||
* targeting the editor preview pane. Uses `excludeAssets` option from | ||
* `HtmlWebpackPlugin` config. | ||
*/ | ||
// Exclude CSS from index.html, as any imported styles are assumed to be | ||
// targeting the editor preview pane. Uses `excludeAssets` option from | ||
// `HtmlWebpackPlugin` config. | ||
new HtmlWebpackExcludeAssetsPlugin(), | ||
|
||
/** | ||
* Pass in needed Gatsby config values. | ||
*/ | ||
// Pass in needed Gatsby config values. | ||
new webpack.DefinePlugin({ | ||
__PATH__PREFIX__: pathPrefix, | ||
CMS_PUBLIC_PATH: JSON.stringify(publicPath), | ||
}), | ||
].filter(p => p), | ||
|
||
/** | ||
* Remove common chunks style optimizations from Gatsby's default | ||
* config, they cause issues for our pre-bundled code. | ||
*/ | ||
// Remove common chunks style optimizations from Gatsby's default | ||
// config, they cause issues for our pre-bundled code. | ||
mode: stage === `develop` ? `development` : `production`, | ||
optimization: { | ||
/** | ||
* Without this, node can get out of memory errors | ||
* when building for production. | ||
*/ | ||
// Without this, node can get out of memory errors when building for | ||
// production. | ||
minimizer: stage === `develop` ? [] : gatsbyConfig.optimization.minimizer, | ||
}, | ||
devtool: stage === `develop` ? `cheap-module-source-map` : `source-map`, | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
value
could be a string - we're recursing the entire received object, in which case!value.test
would throw. Rather than first making sure it's an object and risking some other unforeseen issue, we should just go bulletproof withlodash.get
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if test is a string it will give a falsy value (undefined) when
value.test
is used. So no harm here, thanks for bringing it up to my attention.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No,
value
could be a string. This will throw for some users.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@erquhart do you have an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm not sure why I was thinking that would throw as if
value
is undefined. I know I ran into issues deep mapping the webpack config and needed safe getters, but you're right, this wouldn't be an issue at this line.