// routes.js module.exports = [ { path: '/', exact: true, // component: Home, componentName: 'home' }, { path: '/users', exact: true, // component: UsersList, componentName: 'components/usersList', }, { path: '/users/:id', exact: true, // component: User, componentName: 'components/user', }, ];
const webpack = require('webpack'); //to access built-in const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm const path = require('path'); const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; const nodeEnv = process.env.NODE_ENV || 'development'; const port = Number(process.env.PORT) || 3000; const isDevelopment = nodeEnv === 'development'; const routes = require('../src/react/routes'); const hotMiddlewareScript = `webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000`; const entry = {}; for (let i = 0; i < routes.length; i++ ) { entry[routes[i].componentName] = [ '../src/client.js', '../src/react/' + routes[i].componentName + '.js', ]; if (isDevelopment) { entry[routes[i].componentName].unshift(hotMiddlewareScript); } } module.exports = { name: 'client', target: 'web', cache: isDevelopment, devtool: isDevelopment ? 'cheap-module-source-map' : 'hidden-source-map', context: __dirname, entry, output: { path: path.resolve(__dirname, '../dist'), publicPath: isDevelopment ? '/static/' : '/static/', filename: isDevelopment ? '[name].bundle.js': '[name].[hash].bundle.js', chunkFilename: isDevelopment ? '[name].bundle.js': '[name].[hash].bundle.js', }, module: { rules: [{ test: /\.jsx?$/, exclude: /node_modules/, loader: "babel-loader", options: { cacheDirectory: isDevelopment, babelrc: false, presets: [ 'es2015', 'es2017', 'react', 'stage-0', 'stage-3' ], plugins: [ "transform-runtime", "syntax-dynamic-import", ].concat(isDevelopment ? [ ["react-transform", { "transforms": [{ "transform": "react-transform-hmr", "imports": ["react"], "locals": ["module"] }] }], ] : [ ] ), } } ] }, plugins: [ new webpack.optimize.OccurrenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin(), new webpack.NamedModulesPlugin(), //new webpack.optimize.UglifyJsPlugin(), function(compiler) { this.plugin("done", function(stats) { require("fs").writeFileSync(path.join(__dirname, "../dist", "stats.generated.js"), 'module.exports=' + JSON.stringify(stats.toJson().assetsByChunkName) + ';console.log(module.exports);\n'); }); } ].concat(isDevelopment ? [ ] : [ new CommonsChunkPlugin({ name: "common", minChunks: 2 }), ] ), };
client.js
entry client.js
, the main component for the corresponding route name, and for the development environment also webpack-hot-middleware/client
. new CommonsChunkPlugin({ name: "common", minChunks: 2 }),
minChunks
value allows minChunks
to control the size of the fragments. If set to 2, any section of the same code that is used in the two fragments will be moved to a file named common.bundle.js
. Increasing the value allows reducing the size of the common.bundle.js
module. And increases the size of other fragments. const webpack = require('webpack'); const path = require('path'); const nodeExternals = require('webpack-node-externals'); const externalFolder = new RegExp(`^${path.resolve(__dirname, '../src')}/(react|redux)/.*$`) const nodeEnv = process.env.NODE_ENV || 'development'; const isDevelopment = nodeEnv === 'development'; module.exports = { name: 'server', devtool: isDevelopment ? 'eval' : false, entry: './src/render.js', target: 'node', bail: !isDevelopment, externals: [ nodeExternals(), function(context, request, callback) { if (request == module.exports.entry || externalFolder.test(path.resolve(context, request))){ return callback(); } return callback(null, 'commonjs2 ' + request); } ], output: { path: path.resolve(__dirname, '../src'), filename: 'render.bundle.js', libraryTarget: 'commonjs2', }, module: { rules: [{ test: /\.jsx?$/, exclude: [/node_modules/], use: "babel-loader?retainLines=true" }] } };
devtool: 'eval'
option for developer mode shows in the error message the real file and the line number of the source code. const externalFolder = new RegExp(`^${path.resolve(__dirname, '../src')}/(react|redux)/.*$`); ... function(context, request, callback) { if (request == module.exports.entry || externalFolder.test(path.resolve(context, request))){ return callback(); } return callback(null, 'commonjs2 ' + request); }
'use strict'; const path = require('path'); const createServer = require('http').createServer; const express = require('express'); const port = Number(process.env.PORT) || 3000; const api = require('./src/api/routes'); const app = express(); const serverPath = path.resolve(__dirname, './src/render.bundle.js'); let render = require(serverPath); let serverCompiler const nodeEnv = process.env.NODE_ENV || 'development'; const isDevelopment = nodeEnv === 'development'; app.set('env', nodeEnv); if (isDevelopment) { const webpack = require('webpack'); serverCompiler = webpack([require('./webpack/config.server')]); const webpackClientConfig = require('./webpack/config.client'); const webpackClientDevMiddleware = require('webpack-dev-middleware'); const webpackClientHotMiddleware = require('webpack-hot-middleware'); const clientCompiler = webpack(webpackClientConfig); app.use(webpackClientDevMiddleware(clientCompiler, { publicPath: webpackClientConfig.output.publicPath, headers: {'Access-Control-Allow-Origin': '*'}, stats: {colors: true}, historyApiFallback: true, })); app.use(webpackClientHotMiddleware(clientCompiler, { log: console.log, path: '/__webpack_hmr', heartbeat: 10 * 1000 })); app.use('/static', express.static('dist')); app.use('/api', api); app.use('/', (req, res, next) => render(req, res, next)); } else { app.use('/static', express.static('dist')); app.use('/api', api); app.use('/', render); } app.listen(port, () => { console.log(`Listening at ${port}`); }); if (isDevelopment) { const clearCache = () => { const cacheIds = Object.keys(require.cache); for (let id of cacheIds) { if (id === serverPath) { delete require.cache[id]; return; } } } const watch = () => { const compilerOptions = { aggregateTimeout: 300, poll: 150, }; serverCompiler.watch(compilerOptions, onServerChange); function onServerChange(err, stats) { if (err || stats.compilation && stats.compilation.errors && stats.compilation.errors.length) { console.log('Server bundling error:', err || stats.compilation.errors); } clearCache(); try { render = require(serverPath); } catch (ex) { console.log('Error detecded', ex) } return; } } watch(); }
clearCache(); try { render = require(serverPath); } catch (ex) { console.log('Error detecded', ex) }
import React from "react"; import PropTypes from "prop-types"; import invariant from "invariant"; import { Link, matchPath } from 'react-router-dom'; import routes from './routes'; const isModifiedEvent = event => !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); class AsyncLink extends Link { handleClick = (event) => { if (this.props.onClick) this.props.onClick(event); if ( !event.defaultPrevented && // onClick prevented default event.button === 0 && // ignore everything but left clicks !this.props.target && // let browser handle "target=_blank" etc. !isModifiedEvent(event) // ignore clicks with modifier keys ) { event.preventDefault(); const { history } = this.context.router; const { replace, to } = this.props; function locate() { if (replace) { history.replace(to); } else { history.push(to); } } if (this.context.router.history.location.pathname) { const route = routes.find((route) => matchPath(this.props.to, route) ? route : null); if (route) { import(`${String('./' + route.componentName)}`).then(function() {locate();}) } else { locate(); } } else { locate(); } } }; } export default AsyncLink;
Source: https://habr.com/ru/post/349136/
All Articles