1

我在https://www.shandillia.com/blog上有一个 NextJS 原型。显示的数据是从https://dev.schantillia.com/graphql上的 Strapi 安装中提取的。我还在 Github 上https://github.com/amitschandillia/proost/web(前端)有整个代码库。

我正在使用 Apollo 客户端与 graphql 源进行交互。还有一个服务工作者设置为启用 PWA。

一切正常,除了我无法在浏览器中缓存查询结果。Service Worker 能够缓存除 Apollo 查询结果之外的所有内容。有什么办法可以启用吗?目标是:

  1. 为了能够在服务器上使用某种查询结果的预取。
  2. 能够通过 service worker 将结果缓存在浏览器中。

与此问题相关的三个文件如下:

阿波罗设置


// web/apollo/index.js

import { HttpLink } from 'apollo-link-http';
import { withData } from 'next-apollo';
import { InMemoryCache } from 'apollo-cache-inmemory';

// Set up cache.
const cache = new InMemoryCache();

// Configure Apollo.
const config = {
  link: new HttpLink({
    uri: 'https://dev.schandillia.com/graphql', // Server URL (must be absolute)
  }),
  cache,
};
export default withData(config);

查询组件


// web/pages/PostsList.jsx

import ReactMarkdown from 'react-markdown';
import gql from 'graphql-tag';
import { graphql } from 'react-apollo';
import { Fragment } from 'react';
import Typography from '@material-ui/core/Typography';
import CircularProgress from '@material-ui/core/CircularProgress';

const renderers = {
  paragraph: props => <Typography variant="body1" gutterBottom {...props} />
};

const PostsList = ({ data: { error, posts } }) => {
  let res = '';
  if (error) res = (
    <Typography variant="subtitle2" gutterBottom>
      Error retrieving posts!
    </Typography>
  );
  if (posts && posts.length) {
    if (posts.length !== 0) {
      // Payload returned
      res = (
        <Fragment>
          {posts.map(post => (
            <div>
              <Typography variant="display1" gutterBottom>{post.title}</Typography>
              <Typography variant="subtitle1" gutterBottom>{post.secondaryTitle}</Typography>
              <Typography variant="subtitle2" gutterBottom>Post #{post._id}</Typography>
              <ReactMarkdown source={post.body} renderers={renderers} />
            </div>
          ))}
        </Fragment>
      );
    } else {
      res = (
      // No payload returned
        <Typography variant="subtitle2" gutterBottom>
          No posts Found
        </Typography>
      );
    }
  } else {
    res = (
    // Retrieving payload
      <CircularProgress />
    );
  }
  return res;
};

const query = gql`
  {
    posts {
      _id
      title
      secondaryTitle
      body
    }
  }
`;
// The 'graphql' wrapper executes a GraphQL query and makes the results
// available on the 'data' prop of the wrapped component (PostsList)
export default graphql(query, {
  props: ({ data }) => ({
    data,
  }),
})(PostsList);

博客页面


// web/pages/blog.jsx

import React, { PureComponent, Fragment } from 'react';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import Head from 'next/head';
import Link from 'next/link';
import withRoot from '../lib/withRoot';
import PostsList from '../components/PostsList';

const styles = theme => ({
  root: {
    textAlign: 'center',
    paddingTop: theme.spacing.unit * 20,
  },
  paragraph: {
    fontFamily: 'Raleway',
  },
});

class Blog extends PureComponent {
  constructor(props) {
    super(props);
  }

  componentDidMount() {
    if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceWorker.js'); }
  }

  render() {
    const { classes } = this.props;
    const title = 'Blog | Project Proost';
    const description = 'This is the blog page';
    return (
      <Fragment>
        <Head>
          <title>{ title }</title>
          <meta name="description" content={description} key="description" />
        </Head>
        <div className={classes.root}>
          <Typography variant="display1" gutterBottom>
            Material-UI
          </Typography>
          <Typography gutterBottom>
            <Link href="/about">
              <a>Go to the about page</a>
            </Link>
          </Typography>
          <Typography gutterBottom>
            <Link href="/blog">
              <a>View posts</a>
            </Link>
          </Typography>
          <Button variant="raised" color="primary">
            Super Secret Password
          </Button>
          <Button variant="raised" color="secondary">
            Super Secret Password
          </Button>
        </div>
        <PostsList />
      </Fragment>
    );
  }
}

Blog.propTypes = {
  classes: PropTypes.shape({
    root: PropTypes.string,
  }).isRequired,
};

// Posts.propTypes = {
//   classes: PropTypes.object.isRequired,
// };

export default withRoot(withStyles(styles)(Blog));

有问题的服务人员如下(为简洁起见,已编辑):

// web/offline/serviceWorker.js

const CACHE_NAME = '1b23369032b1541e45cb8e3d94206923';
const URLS_TO_CACHE = [
  '/',
  '/about',
  '/blog',
  '/index',
  'apple-touch-icon.png',
  'browserconfig.xml',
  'favicon-16x16.png',
  'favicon-194x194.png',
  'favicon-32x32.png',
  'favicon.ico',
  'manifest.json',
];

// Call install event
self.addEventListener('install', (e) => {
  e.waitUntil(
    caches
      .open(CACHE_NAME)
      .then(cache => cache.addAll(URLS_TO_CACHE))
      .then(() => self.skipWaiting())
  );
});

// Call activate event
self.addEventListener('activate', (e) => {
  // remove unwanted caches
  e.waitUntil(
    caches.keys().then((cacheNames) => {
      Promise.all(
        cacheNames.map((cache) => {
          if (cache !== CACHE_NAME) {
            return caches.delete(cache);
}
        })
      );
})
  );
});

// Call fetch event
self.addEventListener('fetch', (e) => {
  e.respondWith(
    fetch(e.request).catch(() => caches.match(e.request))
  );
});

请指教!

4

0 回答 0