next-script-for-ga.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. const NodeAttributes = require('../utils/node-attributes.js')
  2. const SUPPORTED_SRCS = [
  3. 'www.google-analytics.com/analytics.js',
  4. 'www.googletagmanager.com/gtag/js',
  5. ]
  6. const SUPPORTED_HTML_CONTENT_URLS = [
  7. 'www.google-analytics.com/analytics.js',
  8. 'www.googletagmanager.com/gtm.js',
  9. ]
  10. const description =
  11. 'Prefer `next/script` component when using the inline script for Google Analytics.'
  12. const url = 'https://nextjs.org/docs/messages/next-script-for-ga'
  13. const ERROR_MSG = `${description} See: ${url}`
  14. // Check if one of the items in the list is a substring of the passed string
  15. const containsStr = (str, strList) => {
  16. return strList.some((s) => str.includes(s))
  17. }
  18. module.exports = {
  19. meta: {
  20. docs: {
  21. description,
  22. recommended: true,
  23. url,
  24. },
  25. type: 'problem',
  26. schema: [],
  27. },
  28. create: function (context) {
  29. return {
  30. JSXOpeningElement(node) {
  31. if (node.name.name !== 'script') {
  32. return
  33. }
  34. if (node.attributes.length === 0) {
  35. return
  36. }
  37. const attributes = new NodeAttributes(node)
  38. // Check if the Alternative async tag is being used to add GA.
  39. // https://developers.google.com/analytics/devguides/collection/analyticsjs#alternative_async_tag
  40. // https://developers.google.com/analytics/devguides/collection/gtagjs
  41. if (
  42. typeof attributes.value('src') === 'string' &&
  43. containsStr(attributes.value('src'), SUPPORTED_SRCS)
  44. ) {
  45. return context.report({
  46. node,
  47. message: ERROR_MSG,
  48. })
  49. }
  50. // Check if inline script is being used to add GA.
  51. // https://developers.google.com/analytics/devguides/collection/analyticsjs#the_google_analytics_tag
  52. // https://developers.google.com/tag-manager/quickstart
  53. if (
  54. attributes.value('dangerouslySetInnerHTML') &&
  55. attributes.value('dangerouslySetInnerHTML').length > 0
  56. ) {
  57. const htmlContent =
  58. attributes.value('dangerouslySetInnerHTML')[0].value.quasis &&
  59. attributes.value('dangerouslySetInnerHTML')[0].value.quasis[0].value
  60. .raw
  61. if (
  62. htmlContent &&
  63. containsStr(htmlContent, SUPPORTED_HTML_CONTENT_URLS)
  64. ) {
  65. context.report({
  66. node,
  67. message: ERROR_MSG,
  68. })
  69. }
  70. }
  71. },
  72. }
  73. },
  74. }