Skip to content

Commit

Permalink
Merge pull request #6 from The-Politico/degulp
Browse files Browse the repository at this point in the history
Degulp
  • Loading branch information
hobbes7878 committed Feb 3, 2019
2 parents 26fabdd + fb6de7e commit 080f5f7
Show file tree
Hide file tree
Showing 26 changed files with 3,695 additions and 733 deletions.
4 changes: 0 additions & 4 deletions .eslintrc

This file was deleted.

21 changes: 21 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"parser": "babel-eslint",
"root": true,
"env": {
"browser": true
},
"rules": {
"indent": ["error", 2],
"semi": ["error", "always"],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "never",
"exports": "never",
"functions": "never"
}],
"operator-linebreak": ["error", "after"],
"space-before-function-paren": ["error", "never"]
},
"extends": ["standard"]
}
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2017 Jon McClure <jmcclure@politico.com>
Copyright (c) 2019 Jon McClure <jmcclure@politico.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
64 changes: 19 additions & 45 deletions docs/using.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ Using
Concepts
--------

The generator builds the structure for a lightweight application that will compile your static assets using Webpack. It uses `Gulp <https://gulpjs.com/>`_ to run the tasks needed to develop and build your scripts for production.
The generator builds the structure for a lightweight application that will compile your static assets using Webpack.

In development, the app will use a tiny `Express <https://expressjs.com/>`_ server to proxy Django's development server, serve your static files and push changes to your browser using `Hot Module Replacement <https://webpack.github.io/docs/hot-module-replacement.html>`_.
In development, the app will proxy Django's development server, serve your static files and push changes to your browser using `Hot Module Replacement <https://webpack.github.io/docs/hot-module-replacement.html>`_.

After you're done developing, the app will build your static assets, which will minify scripts and styles and move them to the normal static directory of your app, i.e., :code:`js/` and :code:`css/` directories.

.. warning::

This app presumes your static directory is structured in the standard Django way. For example: :code:`<your app>/static/<your app>/js/`
This app presumes your static directory is structured in the `standard Django way using namespacing <https://docs.djangoproject.com/en/dev/intro/tutorial06/#customize-your-app-s-look-and-feel>`_. For example: :code:`<your app>/static/<your app>/js/`

Setup
-----
Expand All @@ -38,35 +38,27 @@ Setup
Developing assets
-----------------

To begin developing assets, simply start the Gulp development pipeline in your :code:`staticapp` directory.
To begin developing assets, simply start the development pipeline in your :code:`staticapp` directory.

.. code::
$ gulp
$ yarn start
During development, the app will start a small `Express <https://expressjs.com/>`_ server that will proxy Django's own default Web server, i.e., :code:`runserver`. You can customize the ports used by both Express and Django using the :code:`port` and :code:`proxy` arguments, respectively. They default to :code:`3000` and :code:`8000`.
During development, the app will proxy Django's own default web server, i.e., :code:`runserver`. You can customize the proxied port number using the :code:`proxy` argument, which defaults to :code:`8000`.

.. code::
$ gulp --port 3002 --proxy 8008
.. note::

By default, gulp will run the command to start Django's development server. If you'd rather run it yourself, you can use the :code:`nopython` argument.

.. code::
$ gulp --nopython
$ yarn start --proxy 8008
JavaScript
^^^^^^^^^^

Write your scripts using modern `ES2015 <https://babeljs.io/learn-es2015/>`_ syntax. Babel transforms for React/JSX are also included by default.

In order to build separate scripts for different views in your app, Webpack will look for bundles using a glob pattern :code:`main-*.js*`. So simply prefix any JS or JSX files with :code:`main-` to create a new bundle.
In order to build separate scripts for different views in your app, Webpack will look for bundle entries using a glob pattern :code:`main.*.js*`. So simply prefix any JS or JSX files with :code:`main.` to create a new bundle at the root of your :code:`src/` directory.

For example, these scripts will be compiled into a single bundle, :code:`main-app.js`:
For example, these scripts will be compiled into a single bundle, :code:`main.app.js`:

.. code-block:: javascript
Expand All @@ -89,13 +81,13 @@ For example, these scripts will be compiled into a single bundle, :code:`main-ap
SCSS
^^^^

Import SCSS files in your JavaScript. Do it!
Import SCSS files in your JavaScript.

.. code-block:: javascript
import '../scss/main.scss';
import './theme/base.scss';;
In development, your styles will be injected into your template via JavaScript. When you build your scripts for production, however, the styles will be exported into a separate CSS file in your static directory. See more in Django templates.
As per the POLITICO `JS Apps Style Guide <https://docs.politicoapps.com/politico-newsroom-developer-guide/guides/front-end-apps>`_, SCSS files outside your :code:`theme/` directory will be imported as `CSS modules <https://github.com/css-modules/css-modules>`_.


.. figure:: https://i.makeagif.com/media/7-08-2015/NACqoF.gif
Expand All @@ -111,43 +103,25 @@ In your Django templates, you can reference scripts and styles using Django's `s
{% load static %}
<link rel="stylesheet" href="{% static '<your app>/css/main-app.css' %}" />
<link rel="stylesheet" href="{% static '<your app>/css/main.app.css' %}" />
<script src="{% static '<your app>/js/main-app.js' %}"></script>
<script src="{% static '<your app>/js/main.app.js' %}"></script>
In development, the Express proxy server will serve your JavaScript modules at the location of your app's static directory. For example: :code:`localhost:3000/static/myapp/js/main-app.js`.
In development, the development server will serve your JavaScript modules at the location of your app's static directory. For example: :code:`localhost:3000/static/myapp/js/main.app.js`.

Your styles will be delivered by the Express proxy server in your JavaScript bundle and injected onto the page. This lets Webpack automatically refresh your styles as you develop.
Your styles will be delivered within your JavaScript bundle and injected onto the page. This lets Webpack automatically refresh your styles as you develop.

.. note::

Because the proxy server serves your styles via JavaScript in development, you should see a 404 error in your template for your link tag.

When you build your scripts for production, the styles will be split into a separate file **named after your module.** For example, a module named :code:`main-app.js` that imports some SCSS files like this:

.. code-block:: javascript
// main-app.js
import '../scss/styles.scss';
import '../scss/dataviz.scss';
Will create a CSS bundle named after the module in your app's static folder:

.. code::
css/main-app.css
Which you can then reference in your template:

.. code-block:: django
<link rel="stylesheet" href="{% static '<your app>/css/main-app.css' %}" />
When you build your scripts for production, the styles will be split into a separate file **named after your module.** For example, a module named :code:`main.app.js` will split CSS styles to a stylesheet at :code:`css/main.app.css`.


.. warning::

If you build your static assets and then return to using the development server, keep in mind, that your previously built styles may be included in your template. So using the above example, a stale :code:`main-app.css` may be referenced in your template.
If you build your static assets and then return to using the development server, keep in mind, that your previously built styles may be included in your template. So using the above example, a stale :code:`main.app.css` may be referenced in your template.

If you're simply overwriting styles, the new styles will be injected after the reference to the stale built asset and shouldn't cause a problem, but any other style conflicts may show through.

Expand All @@ -166,6 +140,6 @@ Once you've finished developing assets. Run Gulp's build task inside your :code:

.. code::
$ gulp build
$ yarn build
This will minify your bundles, separate CSS bundles and move scripts and stylesheets to your app's static files folder.
2 changes: 1 addition & 1 deletion docs/why.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ Why this?

At POLITICO, Django is our choice backend, but developing front-end assets in a Python framework isn't always the best experience. For example, to take advantage of the latest JavaScript frameworks, we want to use the latest JS build tools.

This generator represents a package to help seamlessly incorporate a node-based development environment inside a Django application. It creates a build system that integrates directly with Django's normal static files handling while letting you use robust JavaScript module patterns, the latest syntax and stylesheet prepocessors.
This generator helps incorporate a node-based development environment inside a Django application. It creates a build system that integrates directly with Django's normal static files handling pattern while letting you use robust JavaScript module patterns, the latest syntax and prepocessors.

We've found it helps keep our apps better organized and our front-end code as clean and modular as our Python in a way that doesn't require any Django gymnastics.
87 changes: 14 additions & 73 deletions generators/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,107 +7,48 @@ module.exports = class extends Generator {
name: 'appName',
message: 'What\'s your Django app\'s name?',
default: path.basename(path.resolve(process.cwd(), '..')),
}, {
name: 'staticUrl',
message: 'What\'s your STATIC_URL (w/out slashes)?',
default: 'static',
}];

return this.prompt(questions).then((answers) => {
this.appName = answers.appName;
this.staticUrl = answers.staticUrl;
});
}
subgen() {
this.composeWith('politico-interactives:linters');
}
writing() {
// Package meta
this.fs.copyTpl(
this.templatePath('package.json'),
this.destinationPath('package.json'), {
appName: this.appName,
});
// Gulp
this.fs.copy(
this.templatePath('gulpfile.js'),
this.destinationPath('gulpfile.js'));
// Assets
this.fs.copy(
this.templatePath('gulp/index.js'),
this.destinationPath('gulp/index.js'));
this.templatePath('src/main.app.js'),
this.destinationPath('src/main.app.js'));
this.fs.copy(
this.templatePath('gulp/tasks/dev.js'),
this.destinationPath('gulp/tasks/dev.js'));
this.templatePath('src/theme/base.scss'),
this.destinationPath('src/theme/base.scss'));
// Webpack config
this.fs.copyTpl(
this.templatePath('gulp/tasks/build.js'),
this.destinationPath('gulp/tasks/build.js'), {
this.templatePath('webpack.config.dev.js'),
this.destinationPath('webpack.config.dev.js'), {
appName: this.appName,
});
this.fs.copyTpl(
this.templatePath('gulp/server/server.js'),
this.destinationPath('gulp/server/server.js'), {
staticUrl: this.staticUrl,
this.templatePath('webpack.config.prod.js'),
this.destinationPath('webpack.config.prod.js'), {
appName: this.appName,
});
// Assets
this.fs.copy(
this.templatePath('src/js/main-app.js'),
this.destinationPath('src/js/main-app.js'));
this.fs.copy(
this.templatePath('src/scss/main.scss'),
this.destinationPath('src/scss/main.scss'));
// Webpack config
this.fs.copy(
this.templatePath('webpack-dev.config.js'),
this.destinationPath('webpack-dev.config.js'));
this.fs.copyTpl(
this.templatePath('webpack-prod.config.js'),
this.destinationPath('webpack-prod.config.js'), {
appName: this.appName,
});
this.fs.copy(
this.templatePath('postcss.config.js'),
this.destinationPath('postcss.config.js'));
this.fs.copy(
this.templatePath('babelrc'),
this.destinationPath('./.babelrc'));
this.templatePath('eslintrc.json'),
this.destinationPath('./.eslintrc.json'));
this.fs.copy(
this.templatePath('gitignore'),
this.destinationPath('./.gitignore'));
}
install() {
const dependencies = [
'autoprefixer',
'babel-core',
'babel-eslint',
'babel-loader',
'babel-preset-env',
'babel-preset-es2015',
'babel-preset-react',
'express',
'express-http-proxy',
'extract-text-webpack-plugin',
'fs-extra',
'glob',
'gulp',
'lodash',
'node-sass',
'open',
'optimize-css-assets-webpack-plugin',
'postcss-loader',
'react',
'react-dom',
'sass-loader',
'style-loader',
'webpack',
'webpack-dev-middleware',
'webpack-hot-middleware',
'webpack-stream',
'yargs',
];
this.yarnInstall(dependencies, { save: true });
this.yarnInstall();
}
end() {
this.log('Done building you development environment. Run "gulp" to start working!');
this.log('🏁 Done building your development environment. \n\n ⚙️ Run "yarn start" to get going!');
}
};
3 changes: 0 additions & 3 deletions generators/app/templates/babelrc

This file was deleted.

4 changes: 4 additions & 0 deletions generators/app/templates/eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": "@politico/eslint-config-interactives"
}

0 comments on commit 080f5f7

Please sign in to comment.