使用 webpack 和 react-router 进行延迟加载和代码拆分不加载 [英] Using webpack and react-router for lazyloading and code-splitting not loading

查看:54
本文介绍了使用 webpack 和 react-router 进行延迟加载和代码拆分不加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力从客户端移动我的 react v0.14+ redux v3.0 + react-router v1.0 代码库- 端渲染到服务器端渲染使用 webpack v1.12 捆绑和代码拆分成块以按需加载路由和组件.

I'm working on moving my react v0.14+ redux v3.0 + react-router v1.0 codebase from client-side rendering to server-side rendering using webpack v1.12 to bundle and code-split into chunks to load routes and components on-demand.

我关注并基于 https://github.com/rackt/example-react-router-server-rendering-lazy-routes 因为我认为它提供了简单性和出色的实用程序.昨天一整天我都在努力转向服务器端渲染,但我遇到了一些我无法解决的问题,我不完全确定它们是否是因为 webpack 而不是设置正确,如果服务器/客户端或路由配置上的 react-router 有问题,或者我在设置 redux 时做错了什么导致这些问题.

Im following and basing my setup on https://github.com/rackt/example-react-router-server-rendering-lazy-routes as I think it provides simplicity and great utilities. All day yesterday I have been working on moving to server-side rendering but I run into a few issues I haven't been able to solve and I'm not completely sure if they are because of webpack not being setup correctly, if am doing something wrong with react-router on the server/client or the routes config, or if its something I'm doing wrong with setting up redux that is causing these issues.

我遇到了以下问题:

  1. 我能够加载初始页面并且一切正常,但没有其他路由加载并给我 GET http://localhost:3000/profile 404(未找到)
  2. 索引/主页 javascript 可以工作,但所有资产 (css) 都呈现为 text/javascript,因此除非它们是内联的,否则不会显示样式.
  1. I'm able to load the initial page and everything works well but no other routes load and gives me GET http://localhost:3000/profile 404 (Not Found)
  2. The index/home page javascript works but all assets(css) are rendered as text/javascript so the styles don't show up unless they are inline.

webpack.config.js

var fs = require('fs')
var path = require('path')
var webpack = require('webpack')

module.exports = {

  devtool: 'source-map',

  entry: './client/client.jsx',

  output: {
    path: __dirname + '/__build__',
    filename: '[name].js',
    chunkFilename: '[id].chunk.js',
    publicPath: '/__build__/'
  },

  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /(node_modules|bower_components)/,
        loader: 'babel-loader'
      }
    ]
  },

  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compressor: { warnings: false },
    }),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
    })
  ]

}

server.js

import http from 'http';
import React from 'react';
import {renderToString} from 'react-dom/server';
import { match, RoutingContext } from 'react-router';
import {Provider} from 'react-redux';
import configureStore from './../common/store/store.js';

import fs from 'fs';
import { createPage, write, writeError, writeNotFound, redirect } from './server-utils.js';
import routes from './../common/routes/rootRoutes.js';

const PORT = process.env.PORT || 3000;

var store = configureStore();
const initialState = store.getState();

function renderApp(props, res) {
  var markup = renderToString(
    <Provider store={store}>
      <RoutingContext {...props}/>
    </Provider>
  );
  var html = createPage(markup, initialState);
  write(html, 'text/html', res);
}

http.createServer((req, res) => {

  if (req.url === '/favicon.ico') {
    write('haha', 'text/plain', res);
  }

  // serve JavaScript assets
  else if (/__build__/.test(req.url)) {
    fs.readFile(`.${req.url}`, (err, data) => {
      write(data, 'text/javascript', res);
    })
  }

  // handle all other urls with React Router
  else {
    match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
      if (error)
        writeError('ERROR!', res);
      else if (redirectLocation)
        redirect(redirectLocation, res);
      else if (renderProps)
        renderApp(renderProps, res);
      else
        writeNotFound(res);
    });
  }

}).listen(PORT)
console.log(`listening on port ${PORT}`)

服务器工具

与我上面发布的 repo 相同 example-react-router-server-rendering-lazy-routes 只需导航到 /modules/utils/server-utils.js 在 repo 中.唯一的区别是 createPage 函数:

server-utils

Is the same as from the repo that I posted above example-react-router-server-rendering-lazy-routes just navigate to /modules/utils/server-utils.js in the repo.The only difference is the createPage function:

export function createPage(html, initialState) {
  return( `
  <!doctype html>
  <html>
    <head>
      <meta charset="utf-8"/>
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="stylesheet" href="./../bower_components/Ionicons/css/ionicons.min.css">
      <link rel="stylesheet" href="./../dist/main.css">
      <title>Sell Your Soles</title>
    </head>
    <body>
      <div id="app">${html}</div>
      <script>window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};</script>
      <script src="/__build__/main.js"></script>
    </body>
  </html>
  `);
}

rootRoute.js

// polyfill webpack require.ensure
if (typeof require.ensure !== 'function') require.ensure = (d, c) => c(require)

import App from '../components/App.jsx'
import Landing from '../components/Landing/Landing.jsx'

export default {
  path: '/',
  component: App,
  getChildRoutes(location, cb) {
    require.ensure([], (require) => {
      cb(null, [
        require('./UserProfile/UserProfileRoute.js'),
        require('./UserHome/UserHomeRoute.js'),
        require('./SneakerPage/SneakerPageRoute.js'),
        require('./Reviews/ReviewsRoute.js'),
        require('./Listings/ListingsRoute.js'),
        require('./Events/EventsRoute.js')
      ])
    })
  },
  indexRoute: {
    component: Landing
  }
}

userProfileRoute.js

import UserProfile from '../../components/UserProfile/UserProfile.jsx';

export default {
  path: 'profile',
  component: UserProfile
}

client.js

import React from 'react';
import { match, Router } from 'react-router';
import { render } from 'react-dom';
import { createHistory } from 'history';
import routes from './../common/routes/rootRoutes.js';
import {Provider} from 'react-redux';
import configureStore from './../common/store/store.js';


const { pathname, search, hash } = window.location;
const location = `${pathname}${search}${hash}`;

const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);



// calling `match` is simply for side effects of
// loading route/component code for the initial location
match({ routes, location }, () => {
  render(
    <Provider store={store}>
      <Router routes={routes} history={createHistory()} />
    </Provider>,
    document.getElementById('app')
  );
});

推荐答案

我帮助你解决了不和谐问题,但我想我也会在这里发布答案.

I helped you out on discord, but I thought I'd post the answer here as well.

如果您使用 babel6(而不是 babel5)并在组件中使用 export default,则需要将路由更新为以下内容:

If you are using babel6 (instead of babel5) and using export default in your components, then you need to update your routes to the following:

getChildRoutes(location, cb) {
    require.ensure([], (require) => {
        cb(null, [
            require('./UserProfile/UserProfileRoute.js').default,
            require('./UserHome/UserHomeRoute.js').default,
            require('./SneakerPage/SneakerPageRoute.js').default,
            require('./Reviews/ReviewsRoute.js').default,
            require('./Listings/ListingsRoute.js').default,
            require('./Events/EventsRoute.js').default
        ])
    })
}

有关更多详细信息,请参阅此 SO 讨论:Babel 6 更改了导出默认值的方式

See this SO discussion for more details: Babel 6 changes how it exports default

这篇关于使用 webpack 和 react-router 进行延迟加载和代码拆分不加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆