17. Project Structure
Here’s what I did to achieve a structure that I’m able to grasp a bit better.
- Create a
/srcfolder that will hold source files that will be built/transformed - Move the
/Componentsfolder to/src/Components - Move the
/assets/index.jsfile to/src/Pages/index.jsx- We introduced ‘Pages’ here because that’s really what this file was for–page-specific scripts
- Renaming to a .jsx file positions us for using JSX too, even though we’re not yet doing so
- Move the
/index.jsxfile to/src/server.jsx- “server” is really a more appropriate name
- We’ll reserve “index” for pages
- Delete the
/libfolder to get rid of the stale files that were generated - Create a
/binfolder that we’ll start to use instead of/lib
The gulpfile.js needs to be updated to reflect the changes.
var gulp = require('gulp')
, gulpReact = require('gulp-react')
, gulpNodemon = require('gulp-nodemon')
, gulpWatch = require('gulp-watch')
, source = require('vinyl-source-stream')
, browserify = require('browserify')
gulp.task('watch-jsx', ['build'], function() {
gulpWatch('src/**/*.jsx', {
ignored: 'bin/' }, function() {
gulp.start('build')
})
})
gulp.task('jsx', function() {
return gulp.src('src/**/*.jsx')
.pipe(gulpReact())
.pipe(gulp.dest('bin'))
})
gulp.task('build', ['client-scripts'])
gulp.task('client-scripts', ['jsx'], function() {
return browserify('./bin/Pages/index.js').bundle()
.pipe(source('index.js'))
.pipe(gulp.dest('bin/Pages'))
})
gulp.task('node', ['client-scripts', 'watch-jsx'], function() {
gulpNodemon({
script: 'bin/server.js',
ignore: ['gulpfile.js'],
ext: 'js jsx'
})
})
gulp.task('default', function() {
gulp.start('node')
})
After killing the running Gulp process, ensuring the /lib folder is deleted, and restarting Gulp, we’re almost back to working. There are just a few more details to finish below. The end result will be a new structure that will be easier to work with.
/ - Configuration and other general files
/src - Source files that will be built/transformed
/src/Components - React JSX components
/src/Pages - Script files with page-specific code
/bin - Build/transform output
/bin/Components - React components after JSX transform
/bin/Pages - Page-specific script files ready for use in the browser
We’ll make a couple of little housekeeping changes to tidy things up. In /src/server.jsx, we should change the message passed to the <HelloWorld> component and also change the path to the script file to reflect the new structure, and also update our routes to handle requests to /pages. The client will no longer make requests into our Components folder either, because the scripts needed from there get bundled into /pages/index.js, so we can remove that route.
var React = require('react')
, HelloWorld = require('./Components/HelloWorld')
, express = require('express')
, path = require('path')
var app = express()
app.use('/pages', express.static(path.join(__dirname, 'Pages')))
app.get('/', function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'})
var html = React.renderToString(
<html>
<head>
<title>Hello World</title>
</head>
<body>
<HelloWorld from="server.jsx, running on the server" />
<div id="reactContainer" />
<div id="reactHelloContainer"></div>
</body>
<script src="/pages/index.js"></script>
</html>)
res.end(html)
})
app.listen(1337)
console.log('Server running at http://localhost:1337/')
And then in /src/Pages/index.jsx, we’ll make a change to the message it passes to the HelloWorld component too.
var helloInstance = React.createFactory(HelloWorld)( {
from: "index.jsx, transformed and running on the client" } );
Don’t forget to change the references to the Components at the top of /src/Pages/index.jsx.
From: <pre class="brush: js"> var HelloWorld = require(‘../lib/Components/HelloWorld’) var Timestamp = require(‘../lib/Components/Timestamp’) </pre>
To: <pre class="brush: js"> var HelloWorld = require(‘../Components/HelloWorld’) var Timestamp = require(‘../Components/Timestamp’) </pre>
This will reflect the changes to our folder structure. Gulp should build correctly now.