Skip to content

Commit

Permalink
use helmet (#4738)
Browse files Browse the repository at this point in the history
* use helmet

* add e2e test

* fix e2e test

* add unit tests

* add more e2e tests

* update sw.js

* run prod before ssg

* get assets data from prod

* fix npm scripts

* clean up fixture

* update description

* clean up blank line

* test cache busting

* Revert "test cache busting"

This reverts commit 9992136.

* add more e2e tests

* add more tests

* fix test
  • Loading branch information
chenxsan committed Mar 24, 2021
1 parent 4502083 commit d49899f
Show file tree
Hide file tree
Showing 17 changed files with 1,687 additions and 175 deletions.
37 changes: 37 additions & 0 deletions cypress/integration/check-server-side-rendering_spec.js
@@ -0,0 +1,37 @@
describe('server side rendered page', () => {
it('should find meta description', () => {
cy.visit('/guides/getting-started/');
cy.get('head meta[name="description"]').should(
'have.attr',
'content',
'Learn how to bundle a JavaScript application with webpack 5.'
);
});

it('should find html tag with lang', () => {
cy.visit('/');
cy.get('html[lang="en"]');
});

it('should find meta charset', () => {
cy.visit('/');
cy.get('meta[charset="utf-8"]');
});

it('should find the default meta description', () => {
cy.visit('/');
cy.get('head meta[name="description"]').should(
'have.attr',
'content',
'webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.'
);
});

it('should find title', () => {
cy.visit('/');
cy.title().should('eq', 'webpack');

cy.visit('/guides/getting-started/');
cy.title().should('eq', 'Getting Started | webpack');
});
});
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -30,13 +30,13 @@
"clean": "rimraf src/content/**/_*.md src/**/_*.json repositories/*.json",
"start": "npm run clean-dist && webpack serve --config webpack.dev.js --env dev --progress --node-env development",
"content": "node src/scripts/build-content-tree.js ./src/content ./src/_content.json",
"bundle-analyze": "run-s clean fetch printable content && webpack --config webpack.ssg.js --node-env production && run-s clean-printable content && webpack --config webpack.prod.js --node-env production --profile --json > stats.json && webpack-bundle-analyzer stats.json",
"bundle-analyze": "run-s clean fetch content && webpack --config webpack.prod.js --node-env production && run-s printable content && webpack --config webpack.ssg.js --node-env production --profile --json > stats.json && webpack-bundle-analyzer stats.json",
"fetch-repos": "node src/utilities/fetch-package-repos.js",
"fetch": "run-p fetch:*",
"fetch:readmes": "node src/utilities/fetch-package-readmes.js",
"fetch:supporters": "node src/utilities/fetch-supporters.js",
"prebuild": "npm run clean",
"build": "run-s fetch-repos fetch printable content && webpack --config webpack.ssg.js --node-env production && run-s clean-printable content && webpack --config webpack.prod.js --node-env production",
"build": "run-s fetch-repos fetch content && webpack --config webpack.prod.js --node-env production && run-s printable content && webpack --config webpack.ssg.js --node-env production",
"postbuild": "npm run sitemap",
"build-test": "npm run build && http-server --port 4200 dist/",
"test": "npm run lint",
Expand Down Expand Up @@ -152,9 +152,9 @@
"prop-types": "^15.7.2",
"react": "^17.0.2",
"react-banner": "^1.0.0-rc.0",
"react-document-title": "^2.0.3",
"react-dom": "^17.0.2",
"react-g-analytics": "0.4.2",
"react-helmet-async": "^1.0.9",
"react-router-dom": "^5.2.0",
"react-spring": "next",
"react-tiny-popover": "5",
Expand Down
12 changes: 12 additions & 0 deletions src/App.jsx
@@ -0,0 +1,12 @@
import { Route } from 'react-router-dom';
import Site from './components/Site/Site';
export default function App() {
return (
<Route
path="/"
render={(props) => (
<Site {...props} import={(path) => import(`./content/${path}`)} />
)}
/>
);
}
36 changes: 0 additions & 36 deletions src/PrecacheSsgManifestPlugin.js

This file was deleted.

49 changes: 49 additions & 0 deletions src/ProdAssetsManifest.js
@@ -0,0 +1,49 @@
const { Compilation, sources } = require('webpack');

// collect assets data (vendor.[contenthash].js and index.[contenthash].js) for ssg
class ProdAssetsManifest {
apply(compiler) {
let js = [];
let css = [];
compiler.hooks.thisCompilation.tap('ProdAssetsManifest', (compilation) => {
compilation.hooks.processAssets.tap(
{
name: 'ProdAssetsManifest',
stage: Compilation.PROCESS_ASSETS_STAGE_ANALYSE,
},
() => {
for (const [, entrypoint] of compilation.entrypoints) {
const files = entrypoint.getFiles();
js = js.concat(
files
.filter((file) => file.endsWith('.js')) // two js files
.sort((a) => {
// vendor first
if (a.startsWith('vendor')) return -1;
return 1;
})
.map((file) => {
return compilation.outputOptions.publicPath + file;
})
);
css = css.concat(
files
.filter((file) => file.endsWith('.css'))
.sort((a) => {
// index first
if (a.startsWith('index')) return -1;
return 1;
})
.map((file) => compilation.outputOptions.publicPath + file)
);
}
compilation.emitAsset(
'prod-assets-manifest.json',
new sources.RawSource(JSON.stringify({ js, css }))
);
}
);
});
}
}
module.exports = ProdAssetsManifest;
82 changes: 74 additions & 8 deletions src/components/Site/Site.jsx
@@ -1,7 +1,6 @@
// Import External Dependencies
import { Fragment, useEffect, useState } from 'react';
import { Switch, Route, Redirect } from 'react-router-dom';
import DocumentTitle from 'react-document-title';
import PropTypes from 'prop-types';
import { MDXProvider } from '@mdx-js/react';
import { useTransition, animated, config } from 'react-spring';
Expand All @@ -10,6 +9,7 @@ import { useTransition, animated, config } from 'react-spring';
import {
extractPages,
extractSections,
getPageDescription,
getPageTitle,
} from '../../utilities/content-utils';
import isClient from '../../utilities/is-client';
Expand All @@ -29,6 +29,11 @@ import PageNotFound from '../PageNotFound/PageNotFound';
import Vote from '../Vote/Vote';
import Badge from '../Badge/Badge.js';
import { default as LinkComponent } from '../mdxComponents/Link';
import { Helmet } from 'react-helmet-async';

import Favicon from '../../favicon.ico';
import Logo from '../../assets/logo-on-white-bg.svg';
import OgImage from '../../assets/icon-pwa-512x512.png';

// Import Constants
import { THEME, THEME_LOCAL_STORAGE_KEY } from '../../constants/theme';
Expand All @@ -42,6 +47,11 @@ import Content from '../../_content.json';
import NotifyBox from '../NotifyBox/NotifyBox';
import { useLocalStorage } from 'react-use';

const mdxComponents = {
Badge: Badge,
a: LinkComponent,
};

Site.propTypes = {
location: PropTypes.shape({
pathname: PropTypes.string.isRequired,
Expand Down Expand Up @@ -171,15 +181,71 @@ function Site(props) {

// not to show in sub navbar
const excludeItems = ['contribute', 'blog'];

const title = getPageTitle(Content, location.pathname);

const description =
getPageDescription(Content, location.pathname) ||
'webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.';

function isPrintPage(url) {
return url.includes('/printable');
}

// As github pages uses trailing slash, we need to provide it to canonicals for consistency
// between canonical href and final url served by github pages.
function enforceTrailingSlash(url) {
return url.replace(/\/?$/, '/');
}

return (
<MDXProvider
components={{
Badge: Badge,
a: LinkComponent,
}}
>
<MDXProvider components={mdxComponents}>
<div className="site">
<DocumentTitle title={getPageTitle(Content, location.pathname)} />
<Helmet>
<html lang="en" />
<meta charset="utf-8" />
<meta name="theme-color" content="#2B3A42" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{isPrintPage(location.pathname) ? (
<meta name="robots" content="noindex,nofollow" />
) : null}
<title>{title}</title>
<meta name="description" content={description} />
<meta property="og:site_name" content="webpack" />
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta
property="og:description"
name="description"
content={description}
/>
<meta
property="og:image"
content={`https://webpack.js.org${OgImage}`}
/>
<meta property="twitter:card" content="summary" />
<meta property="twitter:site" content="@webpack" />
<meta property="twitter:creator" content="@webpack" />
<meta property="twitter:domain" content="https://webpack.js.org/" />
<link rel="icon" type="image/x-icon" href={Favicon} />
<link rel="manifest" href="/manifest.json" />
<link
rel="canonical"
href={`https://webpack.js.org${enforceTrailingSlash(
location.pathname
)}`}
/>
<meta name="mobile-web-app-capable" content="yes" />
<link rel="icon" sizes="192x192" href="/icon_192x192.png" />
<link rel="icon" sizes="512x512" href="/icon_512x512.png" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="webpack" />
<link rel="apple-touch-icon" href="/icon_180x180.png" />
<link rel="mask-icon" href={Logo} color="#465e69" />
<meta name="msapplication-TileImage" content="/icon_150x150.png" />
<meta name="msapplication-TileColor" content="#465e69" />
</Helmet>
<div className="site__header">
<NotificationBar />
<Navigation
Expand Down
1 change: 1 addition & 0 deletions src/content/guides/getting-started.md
@@ -1,5 +1,6 @@
---
title: Getting Started
description: Learn how to bundle a JavaScript application with webpack 5.
sort: 1
contributors:
- bebraw
Expand Down
5 changes: 1 addition & 4 deletions src/index.html
@@ -1,11 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpack</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
</html>
15 changes: 6 additions & 9 deletions src/index.jsx
@@ -1,13 +1,13 @@
// Import External Dependencies
import ReactDOM from 'react-dom';
import { BrowserRouter, Route } from 'react-router-dom';
import { BrowserRouter } from 'react-router-dom';
import { BrowserRouter as AnalyticsRouter } from 'react-g-analytics';

// Import Components
import Site from './components/Site/Site';
import App from './App.jsx';

// Import helpers
import isClient from './utilities/is-client';
import { HelmetProvider } from 'react-helmet-async';

const isProduction = process.env.NODE_ENV === 'production';

Expand All @@ -18,12 +18,9 @@ const render = isProduction ? ReactDOM.hydrate : ReactDOM.render;
if (isClient) {
render(
<Router id="UA-46921629-2">
<Route
path="/"
render={(props) => (
<Site {...props} import={(path) => import(`./content/${path}`)} />
)}
/>
<HelmetProvider>
<App />
</HelmetProvider>
</Router>,
document.getElementById('root')
);
Expand Down

1 comment on commit d49899f

@vercel
Copy link

@vercel vercel bot commented on d49899f Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.