Commit 57e82506 by Brian Jacobel

Webpack in LMS

parent ec6dfeea
{
"presets": [
["env", {
"targets": {
"browsers": [
"last 2 versions",
"IE >= 11"
]
},
"useBuiltIns": true,
"modules": false,
"exclude": [
"transform-regenerator"
]
}],
"react"
],
"plugins": [
"transform-object-rest-spread"
]
}
...@@ -95,6 +95,8 @@ lms/static/css/ ...@@ -95,6 +95,8 @@ lms/static/css/
lms/static/certificates/css/ lms/static/certificates/css/
cms/static/css/ cms/static/css/
common/static/common/js/vendor/ common/static/common/js/vendor/
common/static/bundles
webpack-stats.json
### Styling generated from templates ### Styling generated from templates
lms/static/sass/*.css lms/static/sass/*.css
......
...@@ -85,6 +85,26 @@ engine = Engine(dirs=settings.DEFAULT_TEMPLATE_ENGINE['DIRS']) ...@@ -85,6 +85,26 @@ engine = Engine(dirs=settings.DEFAULT_TEMPLATE_ENGINE['DIRS'])
source, template_path = Loader(engine).load_template_source(path) source, template_path = Loader(engine).load_template_source(path)
%>${source | n, decode.utf8}</%def> %>${source | n, decode.utf8}</%def>
<%def name="webpack(entry)">
<%doc>
Loads Javascript onto your page from a Webpack-generated bundle.
Uses the Django template engine because our webpack loader only provides template tags for Jinja and Django.
</%doc>
<%
from django.template import Template, Context
return Template("""
{% load render_bundle from webpack_loader %}
{% render_bundle entry %}
<script type="text/javascript">
{% autoescape off %}{{ body }}{% endautoescape %}
</script>
""").render(Context({
'entry': entry,
'body': capture(caller.body)
}))
%>
</%def>
<%def name="require_module(module_name, class_name)"> <%def name="require_module(module_name, class_name)">
<%doc> <%doc>
Loads Javascript onto your page synchronously. Loads Javascript onto your page synchronously.
......
...@@ -1752,6 +1752,16 @@ REQUIRE_JS_PATH_OVERRIDES = { ...@@ -1752,6 +1752,16 @@ REQUIRE_JS_PATH_OVERRIDES = {
'hls': 'common/js/vendor/hls.js' 'hls': 'common/js/vendor/hls.js'
} }
########################## DJANGO WEBPACK LOADER ##############################
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'bundles/',
'STATS_FILE': os.path.join(REPO_ROOT, 'webpack-stats.json'),
}
}
########################## DJANGO DEBUG TOOLBAR ############################### ########################## DJANGO DEBUG TOOLBAR ###############################
# We don't enable Django Debug Toolbar universally, but whenever we do, we want # We don't enable Django Debug Toolbar universally, but whenever we do, we want
...@@ -1950,6 +1960,7 @@ INSTALLED_APPS = ( ...@@ -1950,6 +1960,7 @@ INSTALLED_APPS = (
'edxmako', 'edxmako',
'pipeline', 'pipeline',
'static_replace', 'static_replace',
'webpack_loader',
# For user interface plugins # For user interface plugins
'web_fragments', 'web_fragments',
......
(function(define) { import * as constants from 'edx-ui-toolkit/src/js/utils/constants';
'use strict'; import * as Logger from logger;
define([ export class CourseOutline {
'jquery', constructor(root) {
'logger', document.querySelector(root).addEventListener('keydown', (event) => {
'edx-ui-toolkit/js/utils/constants' const focusable = [...document.querySelectorAll('.outline-item.focusable')];
], const currentFocusIndex = focusable.indexOf(event.target);
function($, Logger, constants) {
return function(root) {
// In the future this factory could instantiate a Backbone view or React component that handles events
$(root).keydown(function(event) {
var $focusable = $('.outline-item.focusable'),
currentFocusIndex = $.inArray(event.target, $focusable);
switch (event.keyCode) { // eslint-disable-line default-case switch (event.keyCode) { // eslint-disable-line default-case
case constants.keyCodes.down: case constants.keyCodes.down:
event.preventDefault(); event.preventDefault();
$focusable.eq(Math.min(currentFocusIndex + 1, $focusable.length - 1)).focus(); focusable[Math.min(currentFocusIndex + 1, focusable.length - 1)].focus();
break; break;
case constants.keyCodes.up: case constants.keyCodes.up:
event.preventDefault(); event.preventDefault();
$focusable.eq(Math.max(currentFocusIndex - 1, 0)).focus(); focusable[Math.max(currentFocusIndex - 1, 0)].focus();
break; break;
} }
}); });
$('a:not([href^="#"])').click(function(event) { document.querySelectorAll('a:not([href^="#"])').addEventListener('click', (event) => {
Logger.log( Logger.log(
'edx.ui.lms.link_clicked', 'edx.ui.lms.link_clicked',
{ {
current_url: window.location.href, current_url: window.location.href,
target_url: event.currentTarget.href target_url: event.currentTarget.href
} }
); );
}); });
}; }
} }
);
}).call(this, define || RequireJS.define);
...@@ -12,10 +12,6 @@ from django.utils.translation import ugettext as _ ...@@ -12,10 +12,6 @@ from django.utils.translation import ugettext as _
from openedx.core.djangolib.markup import HTML, Text from openedx.core.djangolib.markup import HTML, Text
%> %>
<%static:require_module_async module_name="course_experience/js/course_outline_factory" class_name="CourseOutlineFactory">
CourseOutlineFactory('.block-tree');
</%static:require_module_async>
<main role="main" class="course-outline" id="main" tabindex="-1"> <main role="main" class="course-outline" id="main" tabindex="-1">
% if blocks.get('children'): % if blocks.get('children'):
<ol class="block-tree" role="tree"> <ol class="block-tree" role="tree">
...@@ -163,3 +159,7 @@ from openedx.core.djangolib.markup import HTML, Text ...@@ -163,3 +159,7 @@ from openedx.core.djangolib.markup import HTML, Text
<%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory"> <%static:require_module_async module_name="js/dateutil_factory" class_name="DateUtilFactory">
DateUtilFactory.transform('.localized-datetime'); DateUtilFactory.transform('.localized-datetime');
</%static:require_module_async> </%static:require_module_async>
<%static:webpack entry="CourseOutline">
new CourseOutline('.block-tree');
</%static:webpack>
...@@ -20,6 +20,13 @@ ...@@ -20,6 +20,13 @@
"underscore.string": "~3.3.4" "underscore.string": "~3.3.4"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^6.23.0",
"babel-loader": "^6.4.0",
"babel-plugin-react": "^1.0.0",
"babel-plugin-transform-object-rest-spread": "^6.23.0",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.2.1",
"babel-preset-react": "^6.23.0",
"edx-custom-a11y-rules": "0.1.3", "edx-custom-a11y-rules": "0.1.3",
"eslint-config-edx": "^2.0.0", "eslint-config-edx": "^2.0.0",
"eslint-config-edx-es5": "^2.0.0", "eslint-config-edx-es5": "^2.0.0",
...@@ -38,6 +45,8 @@ ...@@ -38,6 +45,8 @@
"pa11y-reporter-json-oldnode": "1.0.0", "pa11y-reporter-json-oldnode": "1.0.0",
"plato": "1.2.2", "plato": "1.2.2",
"sinon": "1.17.3 || >1.17.4 <2.0.0", "sinon": "1.17.3 || >1.17.4 <2.0.0",
"squirejs": "^0.1.0" "squirejs": "^0.1.0",
"webpack": "^2.2.1",
"webpack-bundle-tracker": "^0.2.0"
} }
} }
...@@ -115,6 +115,7 @@ xmltodict==0.4.1 ...@@ -115,6 +115,7 @@ xmltodict==0.4.1
django-ratelimit-backend==1.0 django-ratelimit-backend==1.0
unicodecsv==0.9.4 unicodecsv==0.9.4
django-require==1.0.11 django-require==1.0.11
django-webpack-loader==0.4.1
pyuca==1.1 pyuca==1.1
wrapt==1.10.5 wrapt==1.10.5
zendesk==1.1.1 zendesk==1.1.1
......
const path = require('path');
const webpack = require('webpack');
const BundleTracker = require('webpack-bundle-tracker');
const isProd = process.env.NODE_ENV === 'production';
const wpconfig = {
context: __dirname,
entry: {
CourseOutline: './openedx/features/course_experience/static/course_experience/js/CourseOutline.js',
},
output: {
path: path.resolve(__dirname, 'common/static/bundles'),
filename: '[name]-[hash].js',
libraryTarget: 'window',
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
}),
new webpack.LoaderOptionsPlugin({
debug: !isProd,
}),
new BundleTracker({
filename: './webpack-stats.json'
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
resolve: {
extensions: ['.js', '.json'],
}
};
if (isProd) {
wpconfig.plugins = [
new webpack.LoaderOptionsPlugin({
minimize: true,
}),
new webpack.optimize.UglifyJsPlugin(),
...wpconfig.plugins,
];
}
module.exports = wpconfig;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment