Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

require.context is not a function #48

Closed
phun-ky opened this issue Feb 11, 2016 · 39 comments
Closed

require.context is not a function #48

phun-ky opened this issue Feb 11, 2016 · 39 comments

Comments

@phun-ky
Copy link

phun-ky commented Feb 11, 2016

I'm getting this error when running webpack-isomorphic-tools' withwebpack`

/<dir>/src/content/index.js:9
[1] var contents = require.context('./', true, /content\.yml$/);
[1]                          ^
[1] 
[1] TypeError: require.context is not a function
[1]     at Object.<anonymous> (index.js:2:28)
[1]     at Module._compile (module.js:425:26)
[1]     at loader (/<dir>/node_modules/babel-register/lib/node.js:134:5)
[1]     at Object.require.extensions.(anonymous function) [as .js] (/<dir>/node_modules/babel-register/lib/node.js:144:7)
[1]     at Module.load (module.js:356:32)
[1]     at Function.Module._load (module.js:313:12)
[1]     at Module.require (module.js:366:17)
[1]     at require (module.js:385:17)
[1]     at Object.<anonymous> (/<dir>/src/selectors/index.js:34:16)
[1]     at Module._compile (module.js:425:26)

How to I circumvent/fix this? the code:

var contents = require.context('./', true, /content\.yml$/);

is used to fetch the data files to an array on runtime. The directory tree looks like this:

├── content
│   ├── index.js
│   ├── 2013
│   │   └── content.yml
│   ├── 2014
│   │   └── content.yml
│   ├── 2015
│   │   └── content.yml
│   └── 2016
│       └── content.yml
@catamphetamine
Copy link
Owner

Yes, there's no require.context function emulated on the server side.
What does it do?

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

@halt-hammerzeit the code line above fetches all content.yml files and parses the yaml content via a custom parser and returns it as an array.

This file is bundled with webpack so I don't think it's the issue here. webpack-isomorphic-tools is requiring the content/index.js file containing this code, but I haven't set my webpack-isomorphic-tools-configuration file to do anything with the javascript files :S

So, could this just be the tool trying to require javascript files (and this error occurs) when it shouldn't?

EDIT: Hm, well, the tool has to "scrape" the javascript files to figure out what to extract..

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

@halt-hammerzeit could it be that your tool is figuring out what is to be required and tries to follow that require to find more files to be "isomorphed", but the tool is not capable of following require.context-calls?

@catamphetamine
Copy link
Owner

I asked you not about what your code does but about what require.context does.

Seems that it is used for dynamic require()s
https://webpack.github.io/docs/context.html

You can create your own context with the require.context function. It allow to pass a directory, regular expression and a flag if subdirectories should be used too.

require.context(directory, useSubdirectories = false, regExp = /^\.\//)

This require.context function exists inside Webpack but it doesn't exist in Node.js hence the error.
You may want to rewrite your code so that this line of code is not executed on the server side.

@catamphetamine
Copy link
Owner

could it be that your tool is figuring out what is to be required and tries to follow that require to find more files to be "isomorphed", but the tool is not capable of following require.context-calls?

The tool instruments require() function in Node.js so that it knows how to load non-js file types.
That's it.

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

@halt-hammerzeit err, how would I do that? The file has to be called, ref:

 [webpack-isomorphic-tools] [debug] require("content") was called (...)

Hm, could I wrap this in a try catch?

@catamphetamine
Copy link
Owner

err, how would I do that?

Can't tell until I see the code

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

Sorry, I am a bit frustrated with getting server-side rendering to work here and this is blocker number "n+1", so bare with me on this 😫

This is the content of content\index.js:

//this file includes all contents indexed by directory name
const contents = require.context('./', true, /content\.yml$/);

const contentArray = contents.keys().map(key => (
  contents(key)
));

let contents = {};
contentArray.forEach(contentContainer => contents[contentContainer.id] = contentContainer);

export default contents;

//require all images as well
const imageFiles = require.context('./', true, /\.(jpg|jpeg|png|svg)$/);
const imagePaths = imageFiles.keys();

export function getImageUrl(contentId, pointId) {
  const pattern = new RegExp(`^./${contentId}/points/${pointId}\\.(jpg|jpeg|png|svg)$`);
  const image = imagePaths.find(p => pattern.test(p));
  return image && imageFiles(image);
}

export function getCoverImage(contentId) {
  const pattern = new RegExp(`^./${contentId}/cover\\.(jpg|jpeg|png|svg)$`);
  const image = imagePaths.find(p => pattern.test(p));
  return image && imageFiles(image);
}

And the files is imported from another file which provides memoized selectors for the entire application:

import contentContainers from 'content';

The clue here is that the application will never know the number of content folders, it will only know that there exists n+1 content.yml-files in the subdirectories

@catamphetamine
Copy link
Owner

Well, for example, you could do something like this:

//this file includes all contents indexed by directory name
let contents

if (__CLIENT__)
{
  contents = require.context('./', true, /content\.yml$/);
}
else
{
  const path = require('path')
  const fs = require('fs')
  for (let child of fs.readdirSync(__dirname))
  {
    console.log(child)
    if (fs.statSync(path.join(__dirname, child)).isDirectory())
    {
      contents[path] = require(path.join(__dirname, child, 'content.yml'))
    }
  }
}

__CLIENT__ may be set in your Webpack DefinePlugin, for example.

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

In pseudo-code, I think this could be solved like this:

if node
  read all 'content.yml*'-files within directory

  loop through files
    require(path + 'content.yml')
else
  use require.context

@catamphetamine
Copy link
Owner

Or you can implement require.context function in webpack-isomorphic-tools and send a Pull Request.

I have added this feature to the To do list for whoever wants to implement this in the future:

* Implement `require.context(folder, include_subdirectories, regular_expression)` Webpack helper function

catamphetamine added a commit that referenced this issue Feb 11, 2016
@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

@halt-hammerzeit ok, I got the code running, but stuck with a new problem, how can I implement the loader logic on these files? The yml files is now required raw without the loader:

/<dir>/src/content/index.js:53
[1]         throw _iteratorError;
[1]         ^
[1] 
[1] SyntaxError: /<dir>/src/content/2013/content.yml: Unexpected token (1:17)
> 1 | title: Year 2013

The code:

// fix for require.context on server side rendering
// see https://github.com/halt-hammerzeit/webpack-isomorphic-tools/issues/48
let contents;

if(__CLIENT__){
  contents = require.context('./', true, /content\.yml$/);
} else {
  const contentDir = './src/content/';

  for (let child of fs.readdirSync(contentDir)){
    console.log(child)
    if (fs.statSync(path.join(contentDir, child)).isDirectory()){
      contents[path] = require(path.join(__dirname, child, 'content.yml'));
    }
  }
}

I've tried to include the loader directly:

contents[path] = contentLoader(fs.readFileSync(path.join(__dirname, child, 'content.yml')));

But that results in error because of missing the this-context

@catamphetamine
Copy link
Owner

So you are telling that require() calls on the server side don't know how to require yml files?
They should.
Post your debug log and your webpack-isomorphic-tools config.

@dtothefp
Copy link

@phun-ky yes this is a problem stemming from developing your code in webpack which completely redefines it's version of require and then running the code in Node to do isomorphic. webpack-isomorphic-tools attempts to solve this but can't do everything and once you solve this problem you may run into others where your client code uses references or libs that reference browser stuff like document, etc. my solution is to still use isomorphic tools for stats generation because it is awesome for that and then compile all my isomorphic entries with webpack target: node. Then I can easily create a loader that reads any of my asset requires from stats json and another that mocks any browser syntax that is breaking in node. Then you can just require your webpack bundles (assuming you compile with output commonjs) and call reacts render to string on them.

I believe @halt-hammerzeit has an example repo where he does something similar but much more eloquently https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example

@catamphetamine
Copy link
Owner

For anyone who got here from Google or from the To do list:

While looking for a possibility to implement require.context function I currently see no clean way to do it (there is a dirty way in the end of this message).

The require() function is created in the internal/module module to which we have no access
https://github.com/nodejs/node/blob/master/lib/module.js#L413
https://github.com/nodejs/node/blob/7c603280024de60329d5da283fb8433420bc6716/lib/internal/module.js#L9

If there was a way to get a hold of that require variable before it is passed to module compilation function then it would be possible to inject a context property into it.
Alternatively the makeRequireFunction function could be instrumented if we had a way to import the internal/module module and modify its exports.

The function itself would look like this:

require.context = function(base, scan_subdirectories, regular_expression) {
  const contents = {}

  function read_directory(directory) {
    for (let child of fs.readdirSync(directory)) {
      const full_path = path.join(directory, child)
      if (fs.statSync(full_path).isDirectory()) {
        if (scan_subdirectories) {
          read_directory(full_path)
        }
      } else {
        if (regular_expression && !regular_expression.match(full_path)) {
          continue
        }
        contents[path.relative(base, full_path)] = require(full_path)
      }
  }

  read_directory(base)

  return contents
}

The dirty way I found is:

const original_compile = require('module').prototype._compile
require('module').prototype._compile = function(content, filename)
{
    var preamble = ''

    if (starts_with(content, `'use strict'`) || starts_with(content, `"use strict"`))
    {
        preamble = `"use strict";`
    }

    preamble += `require.context = function() { console.log('require.context code here') };;;` 

    content = preamble + content

    // return value is undefined
    return original_compile.call(this, content, filename)
}

It's "dirty" because it prepends some code to the require()d module code therefore leaving traces.
But it works, i tried (this code has to be executed before the module of interest is require()d).

@catamphetamine
Copy link
Owner

@dtothefp Oh, hi there. Thanks for participation.

@chrisblossom
Copy link
Contributor

@dtothefp Could you please post an example how you are accomplishing this? I am trying to do the exact same thing but I can't seem to get my image assets to line up.

Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally
 means that you are using server rendering and the markup generated on the server was not what the 
client was expecting. React injected new markup to compensate which works but you have lost many of 
the benefits of server rendering. Instead, figure out why the markup being generated is different on the 
client or server:
 (client) 6o.1.1.0"><img src="http://localhost:300
 (server) 6o.1.1.0"><img src="6d6e4f72d35d82908482

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

So much trouble, and all I want is to let the server (index.html) know about the store (react-redux) so it can update the meta-tags based on which page you are on :/ #fml

Will see if I can get something to work :S

@dtothefp
Copy link

@chrisblossom you are essentially doing something flux/state wise on the server different from client, ie if you are toggling a class based on query params/cookie/async-something before componentDidMount. That warning doesn't show the exact location but looks like it's mad about your hashed publicPath.

I ended up making a queue for client actions and then don't emit these actions until componentDidMount on the top level component fires

@dtothefp
Copy link

@chrisblossom @phun-ky below are some examples of the way I do it using a static template generator with Nunjucks

//stats loader
import path from 'path';
import fs from 'fs-extra';
import renameKey from '../../../utils/rename-key';

/**
 * Webpack loader used for "SERVER" build to load local
 * assets such as Images and CSS from the stats created
 * by Webpack Isomporphic Tools
 * @param {Buffer} content
 * @return {undefined} uses the `cb` callback to pass data to the `compiler`
 */
export default function(content) {
  this.cacheable && this.cacheable();
  const cb = this.async();
  const resourcePath = renameKey(this.resourcePath);

  fs.readJson(path.join(process.cwd(), 'dist', 'webpack-main-stats.json'), (err, data) => {
    if (err) {
      cb(err);
    } else {
      const {assets} = data;
      const [assetData] = Object.keys(assets).reduce((list, assetPath) => {
        const asset = assets[assetPath];

        return resourcePath === renameKey(assetPath) ? [...list, asset] : list;
      }, []);

      cb(null, `module.exports = ${JSON.stringify(assetData)};`);
    }
  });
}

//mocks loader
/**
 * Webpack loader used for "SERVER" build to load local
 * assets such as Images and CSS from the stats created
 * by Webpack Isomporphic Tools
 * @param {Buffer} content
 * @return {undefined} uses the `cb` callback to pass data to the `compiler`
 */
export default function(content) {
  const mocks = [
    {
      re: /(?:global|window)?\.?ga\(/,
      sub: 'global.ga = () => {}'
    },

    {
      re: /(?:global|window)?\.?Raven\.captureException\(/,
      sub: 'global.Raven = {captureException: () => {}}'
    },

    {
      re: /(?:global|window)?\.?optimizely\./,
      sub: 'global.optimizely = {push: () => {}}'
    },

    {
      re: /navigator\..+$/,
      sub: `navigator = {
        userAgent: '',
        geolocation: {
          getCurrentPosition() {}
        }
      }`
    },

    {
      re: /(?:global|window)?\.?silverpop\./,
      sub: 'global.silverpop = {trackEvent: () => {}, flush: () => {}}'
    },

    {
      re: /document\.?(?:cookie|documentElement)?/,
      sub: `global.document = {
        get cookie() {
          return '';
        },
        set cookie(val) {},
        cookie: {
          split() {}
        },
        documentElement: {
          style: {}
        }
      }`
    }
  ];

  const mockSubs = mocks.reduce((str, data) => {
    const {re, sub} = data;

    if (re.test(content)) {
      str = `\n${sub}\n` + str;
    }

    return str;
  }, '');

  return mockSubs + content;
}

//loaders.js
    {
      test: toolsPlugin.regular_expression('images'),
      loader: SERVER ? join(__dirname, 'iso-tools-stats-loader') : fileLoader
    },
      cssLoader = [
        join(__dirname, 'iso-tools-stats-loader'),
        'postcss-loader'
      ].join('!');

Obviously with this approach you need to build your complete bundle first so you have all the stats from webpack-isomorphic-tools

//static template generation loader
import glob from 'globby';
import webpack from 'webpack';
import MemoryFS from 'memory-fs';
import gutil from 'gulp-util';
import renameKey from '../../utils/rename-key';
import makeConfig from '../../config';
import makeWebpackConfig from '../webpack/make-webpack-config';
import compile from '../../utils/compile-module';

const {colors, log} = gutil;
const {magenta, blue} = colors;

/**
 * Loader to compile React components and es6 functions with Webpack
 * memory-fs and put them on the `snippets` Assemble collection
 *
 * @param {Object} collection instance provided by assemble
 *
 * @return {Function} function re-defining a `load` method
 */
export default function(collection) {
  /**
   * @param {String|Array} patterns glob patterns
   * @param {Object} options glob options
   * @param {Object} data any additional context
   * @param {Function} cb callback to be called at the end
   *
   * @return {undefined} use the cb
   */
  collection.load = (patterns, options = {}, data = {}, cb) => {
    const files = glob.sync(patterns, options);
    const entry = files.reduce((acc, fp) => {
      const name = renameKey(fp);
      log(`Compiling ${magenta(name)} component for isomorphic build`);

      return {
        ...acc,
        [name]: [fp]
      };
    }, {});

    const config = makeConfig({
      ENV: 'server',
      entry
    });
    const fs = new MemoryFS();
    const webpackConfig = makeWebpackConfig(config);

    webpackConfig.plugins.push(
      function() {
        this.plugin('done', (stats) => {
          const {errors} = stats.compilation || {};

          if (errors && errors.length) {
            log(errors);
          }
        });
      }
    );

    const compiler = webpack(webpackConfig);
    const {sources, utils} = config;
    const {buildDir, scriptDir} = sources;
    const {addbase} = utils;

    compiler.outputFileSystem = fs;

    compiler.run((err, stats) => {
      if (err) return cb(err);

      Object.keys(entry).forEach(file => {
        const filename = `${file}.js`;
        const fp = addbase(buildDir, scriptDir, filename);
        log(`Finished Compiling ${blue(file)} component`);
        const contents = fs.readFileSync(fp);


        collection.addView(file, {
          path: file,
          contents,
          fn: compile(contents)
        });
      });
      cb(null);
    });
  };
}

//compile
import _ from 'lodash';

/**
 * Utility to extract a string of JS into JavaScript "runnable" code
 * @param {String} content pre-combiled string of JS code
 * @param {String|undefined} key property to pull off of `module.exports`
 *
 * @return {Funtion|Object} string converted to "runnable" JS
 */
export default function(content, key) {
  const compileTarget = _.isFunction(content.toString) ? content.toString() : content;
  const m = new module.constructor();
  m.paths = module.paths;
  m._compile(compileTarget);

  return key ? m.exports[key] : m.exports;
}

@phun-ky
Copy link
Author

phun-ky commented Feb 11, 2016

@dtothefp : will try that tomorrow and see if I get any further.

@chrisblossom
Copy link
Contributor

@dtothefp Thanks for the response. Could you also post your webpack client and server build configuration? I think I may have misunderstood what you are doing.

I fixed my issue by using the same output.publicPath for my node webpack config as my client. I am not 100% sure if the server is fully rendering the page though.

@catamphetamine
Copy link
Owner

@chrisblossom

 (client) 6o.1.1.0"><img src="http://localhost:300
 (server) 6o.1.1.0"><img src="6d6e4f72d35d82908482

You seem to not prepending webpack configuration's output.publicPath to the image url on the server.
webpack-isomorphic-tools would do that for you automatically

@catamphetamine
Copy link
Owner

@phun-ky

So much trouble, and all I want is to let the server (index.html) know about the store (react-redux) so it can update the meta-tags based on which page you are on

You can do that using react-helmet or react-document-meta easily.
I'm doing it in my webapp using react-document-meta
https://github.com/halt-hammerzeit/react-isomorphic-render/blob/master/source/webpage%20head.js

If you feel a need for a specific example with react-redux you can check out my sample webapp boilerplate
https://github.com/halt-hammerzeit/webapp

@chrisblossom
Copy link
Contributor

@halt-hammerzeit thank you, that was exactly my issue.

Because I am using webpack for both my frontend and backend, I am running them both though the same loaders. I think this solves most of what webpack-isomorphic-tools does with the exception of asset tracking.

Currently I am using webpack-isomorphic-tools to export webpack-assets.json to load assets in html.js.

Is there a benefit I am missing out on from webpack-isomorphic-tools by doing this?

@catamphetamine
Copy link
Owner

@chrisblossom I guess you don't miss anything. It's just a question of why write your own asset loading mechanism if it's already written.

@chrisblossom
Copy link
Contributor

@halt-hammerzeit Using webpack-isomorphic-tools for that. Still smoothing out the edges on this, but basically:

dev.client.webpack.config.js:

...
import WebpackIsomorphicToolsPlugin from 'webpack-isomorphic-tools/plugin';
import webpackIsomorphicToolsPluginConfig from './webpack_isomorphic_tools';

import NodeExternals from 'webpack-node-externals';
const nodeModules = new NodeExternals();

const sharedConfig = {
  ...
  module: {
    loaders: [{
      test: /\.scss$/,
      loader: ExtractTextPlugin.extract('style',
        'css?modules&importLoaders=2&localIdentName=[local]___[hash:base64:5]!postcss!sass?outputStyle=expanded&sourceMap=true' +
        '&sourceMapContents=true'),
    }, {
      test: /\.png$/,
      loader: 'url-loader?limit=1',
    }],
  },
  ...
}

const clientConfig = {
...
  output: {
    path: buildPath,
    filename: '[name].js',
    chunkFilename: '[name]-[chunkhash].js',
    publicPath: `http://${host}:${webpackHmrPort}/dist/`,
  },
  target: 'web',
  plugins: [
    ...
    new WebpackIsomorphicToolsPlugin(webpackIsomorphicToolsPluginConfig),
    ...  
  ],
  ...
}

// Possibly move global universalAssets to server.js. At very least rename.
const serverConfig = {
  ...
  output: {
    path: buildPath,
    filename: outputFile,
    libraryTarget: 'commonjs2',
    publicPath: `http://${host}:${webpackHmrPort}/dist/`,
  },
  target: 'node',
  externals: [nodeModules],
  plugins: [
    ...
    new webpack.DefinePlugin(
      universalAssets: JSON.stringify(require(path.resolve(projectRootPath, 'webpack-assets.json')))
    ),
    ...  
  ],
  ...
}

// Merge configs

server.js:

...
  res.send(`<!doctype html>\n${ReactDOM.renderToString(
    <Html assets={universalAssets} component={component} store={store}/>)}`)
...

The biggest downside to this I've found so far is it writes assets twice. I am sure I can find a workaround for that though. I am correct in thinking requiring webpack-assets.json directly opposed something like this below will yield the same results:

...
const webpackIsomorphicTools = new WebpackIsomorphicTools(WebpackIsomorphicToolsConfig);
  webpackIsomorphicTools
    .development()
const serverConfig = {
  ...
  plugins: [
    ...
    new webpack.DefinePlugin(
      universalAssets: JSON.stringify(webpackIsomorphicTools.assets())
    ),
    ...  
  ],
  ...

Btw, the reason I am using webpack for the backend is because babel does not recommend using babel-register in production.

@catamphetamine
Copy link
Owner

@chrisblossom hmm, interesting solution. you're defining a global variable holding the assets, i see...

babel does not recommend using babel-register in production.

Oh, didn't know about that.
If that's so then compiling with Webpack might be the way to go.

The biggest downside to this I've found so far is it writes assets twice.

Didn't understand that line but don't mind

@chrisblossom
Copy link
Contributor

See: http://babeljs.io/docs/setup/#babel_register

Not meant for production use
The require hook is primarily recommended for simple cases.

I plan to move the global variable to a local defined var inside of server.js

Webpack is running two separate configs so each file is ran through the loader twice. This means image_.png and style_.css will be written to the build directory of the node config and the client config.

https://github.com/webpack/webpack/tree/master/examples/multi-compiler

modules.export = [
{
// Client config
},

{
// Node config
}
];

@catamphetamine
Copy link
Owner

@chrisblossom oh, didn't know that it writes the assets twice.
ok.

By the way, I implemented support for require.context(): in order for it to work the user is required to enable require_context: true flag in the configuration.
It should work.

Update: webpack-isomorphic-tools@2.2.27

catamphetamine added a commit that referenced this issue Feb 11, 2016
@phun-ky
Copy link
Author

phun-ky commented Feb 12, 2016

@halt-hammerzeit an update regarding the loading of *.yml files:

So you are telling that require() calls on the server side don't know how to require yml files?
They should.
Post your debug log and your webpack-isomorphic-tools config.

The error:

[1] /<dir>/src/content/index.js:11
[1] var contentsArray = contents.keys().map(function (key) {
[1]                             ^
[1] 
[1] TypeError: contents.keys is not a function
[1]     at Object.<anonymous> (index.js:4:31)
[1]     at Module._compile (module.js:425:26)
[1]     at Module.require._compile (/<dir>/node_modules/webpack-isomorphic-tools/babel-transpiled-modules/index.js:356:28)
[1]     at loader (/<dir>/node_modules/babel-register/lib/node.js:134:5)
[1]     at Object.require.extensions.(anonymous function) [as .js] (/<dir>/node_modules/babel-register/lib/node.js:144:7)
[1]     at Module.load (module.js:356:32)
[1]     at Function.Module._load (module.js:313:12)
[1]     at Module.require (module.js:366:17)
[1]     at require (module.js:385:17)
[1]     at Object.<anonymous> (/<dir>/src/selectors/index.js:34:16)

My config:

import webpack_isomorphic_tools_plugin from 'webpack-isomorphic-tools/plugin';
import path from 'path';

const srcPath = path.join(__dirname, '/../src');

module.exports = {
  debug: true,
  verbose: true,
  require_context: true,
  alias: {
    actions: srcPath + '/actions/',
    components: srcPath + '/components/',
    containers: srcPath + '/containers/',
    content: srcPath + '/content/',
    store: srcPath + '/store/',
    styles: srcPath + '/styles/',
    config: srcPath + '/config/' + process.env.NODE_ENV
  },
  assets:{
    images: {
      extensions: ['png', 'jpg', 'gif', 'ico'],
      parser: webpack_isomorphic_tools_plugin.url_loader_parser
    },
    svg: {
      extension: 'svg',
      parser: webpack_isomorphic_tools_plugin.url_loader_parser
    },
    radars: {
      extension: 'yml',
      parser: webpack_isomorphic_tools_plugin.url_loader_parser
    }
  }
};

And the assets file: https://gist.github.com/phun-ky/8c808054a53cd57333f3 ( I am not obfuscating directories/variables now, takes too long 😛 )

The stats file: https://gist.github.com/phun-ky/96f0277c59c6cddd5f5b

And this is the loader I want to use: https://gist.github.com/phun-ky/e8ed6778c367bcdbd36d

@catamphetamine
Copy link
Owner

@phun-ky Well, why do you think that context has .keys()?
Try Object.keys(context) for example.

Also, after you get this thing working, try out the new version which supports require.context and tell me if it works (set require_context: true flag in the config)

@phun-ky
Copy link
Author

phun-ky commented Feb 12, 2016

@halt-hammerzeit The code above is with the latest version, forgot to mention that. The require.context returns an array (due to the loader) without isomorphic tools. The issue is that the loader is not kicking in.

@phun-ky
Copy link
Author

phun-ky commented Feb 12, 2016

@chrisblossom regarding: #48 (comment) , I am trying this approach. But would you have all loaders in the shared config? When should I use the extract plugin, and when should I use the isomorphic plugin?

catamphetamine added a commit that referenced this issue Feb 12, 2016
@catamphetamine
Copy link
Owner

@phun-ky oh, a sophisticated loader you have. never imagined people would do that. ok, that's an interesting approach.

regarding your error message, I get it now: require.context() should return something with .keys() function.
I can do that.

Try webpack-isomorphic-tools@2.2.28.
Now it has .keys() and such.

@phun-ky
Copy link
Author

phun-ky commented Feb 12, 2016

@dtothefp regarding #48 (comment), what is renameKey?

I'm trying to bind it all together:

  • A web-pack config for dev.client
  • A web-pack config for dev.server
  • A dev server (port 8000)
  • A webpack-dev-server (for HOT)(port 8000 ??)
  • Using ExtractTextWebpackPlugin on pure CSS and fonts(in shared config across envs and client/server)
  • Using native (webpack)-loaders for Stylus and javascript/jsx (in shared config across envs and client/server)
  • Using isomorphic test for loaders for images, svg and yml files (in dev client config, (should I use this on server aswell?)

And what should be different with these in development/production?

@phun-ky
Copy link
Author

phun-ky commented Feb 12, 2016

@halt-hammerzeit regarding

If you feel a need for a specific example with react-redux you can check out my sample webapp boilerplate
https://github.com/halt-hammerzeit/webapp

I would'nt call that amount of code for a boiler plate :S Tried to take a look at it now and it's a bit confusing to say at least.

This whole thing becomes off topic, but I am more close the the "going postal" point than solving this. Going away for a week, need to clear my mind. Will abandon this thread if nothing more comes. Thanks for the patience.

@catamphetamine
Copy link
Owner

@phun-ky ok, at least the initial issue with require.context is resolved now.

There's nothing difficult in the world once you learn how to formulate the right questions.
Pure logic, saves nerves.

@catamphetamine
Copy link
Owner

FYI
I'm posting this in every issue and PR to notify whoever may be interested:
today I've released an alternative helper library called universal-webpack.
It takes a different approach than webpack-ismorphic-tools and instead of hacking Node.js require() calls it just compiles all code with target: 'node' webpack configuration option.
As a result, all Webpack plugins and features are supported.
If you think you might need that here's an example project:
https://github.com/halt-hammerzeit/webpack-react-redux-isomorphic-render-example

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants