diff --git a/.babelrc b/.babelrc index eb52c30ac19b..bd9c86c1e126 100644 --- a/.babelrc +++ b/.babelrc @@ -8,7 +8,5 @@ } ] ], - "plugins": [ - "transform-es2015-modules-strip" - ] + "plugins": ["external-helpers"] } diff --git a/build/rollup.config.js b/build/rollup.config.js new file mode 100644 index 000000000000..7cec6ef1cc99 --- /dev/null +++ b/build/rollup.config.js @@ -0,0 +1,43 @@ +const path = require('path') +const babel = require('rollup-plugin-babel') +const resolve = require('rollup-plugin-node-resolve') +const BUNDLE = process.env.BUNDLE === 'true' + +var fileDest = 'bootstrap.js' +var external = ['jquery', 'popper.js'] +const plugins = [ + babel({ + exclude: 'node_modules/**', // only transpile our source code + externalHelpersWhitelist: [ // include only required helpers + 'typeof', + 'classCallCheck', + 'createClass', + 'inherits', + 'possibleConstructorReturn' + ] + }) +] +const globals = { + jquery: '$', + 'popper.js': 'Popper' +} + +if (BUNDLE) { + fileDest = 'bootstrap.bundle.js' + // remove last entry in external array to bundle Popper + external.pop() + delete globals['popper.js'] + plugins.push(resolve()) +} + +module.exports = { + input: path.resolve(__dirname, '../js/src/index.js'), + output: { + file: path.resolve(__dirname, `../dist/js/${fileDest}`), + format: 'iife' + }, + name: 'bootstrap', + external: external, + globals: globals, + plugins: plugins +} diff --git a/build/stamp.js b/build/stamp.js index 8cde189d7ff3..2135c60a3b82 100644 --- a/build/stamp.js +++ b/build/stamp.js @@ -1,41 +1,19 @@ -const fs = require('fs') +const fs = require('fs') +const path = require('path') +const pkg = require(path.resolve(__dirname, '../package.json')) +const year = new Date().getFullYear() -fs.readFile('package.json', (err, data) => { - if (err) { - throw err - } +const pathBoostrap = path.resolve(__dirname, '../dist/js/bootstrap.js') +const pathBootstrapBundle = path.resolve(__dirname, '../dist/js/bootstrap.bundle.js') +const contentFile = fs.readFileSync(pathBoostrap, { encoding: 'UTF8' }) +const contentBundleFile = fs.readFileSync(pathBootstrapBundle, { encoding: 'UTF8' }) - const pkg = JSON.parse(data) - const year = new Date().getFullYear() - - const stampTop = +const stamp = `/*! * Bootstrap v${pkg.version} (${pkg.homepage}) * Copyright 2011-${year} ${pkg.author} * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) */ - -if (typeof jQuery === 'undefined') { - throw new Error('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.') -} - -(function ($) { - var version = $.fn.jquery.split(' ')[0].split('.') - if ((version[0] < 3) || (version[0] >= 4)) { - throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v3.0.0 but less than v4.0.0') - } -})(jQuery); - -(function () { ` - const stampEnd = ` -})();` - - process.stdout.write(stampTop) - - process.stdin.on('end', () => { - process.stdout.write(stampEnd) - }) - - process.stdin.pipe(process.stdout) -}) +fs.writeFileSync(pathBoostrap, `${stamp}${contentFile}`, { encoding: 'UTF8' }) +fs.writeFileSync(pathBootstrapBundle, `${stamp}${contentBundleFile}`, { encoding: 'UTF8' }) diff --git a/js/src/alert.js b/js/src/alert.js index b6b9336af79e..9fcf088b1283 100644 --- a/js/src/alert.js +++ b/js/src/alert.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Alert = (($) => { +const Alert = (() => { /** diff --git a/js/src/button.js b/js/src/button.js index a8a72ef56981..a121b8e13aa0 100644 --- a/js/src/button.js +++ b/js/src/button.js @@ -1,3 +1,4 @@ +import $ from 'jquery' /** * -------------------------------------------------------------------------- * Bootstrap (v4.0.0-beta): button.js @@ -5,7 +6,7 @@ * -------------------------------------------------------------------------- */ -const Button = (($) => { +const Button = (() => { /** diff --git a/js/src/carousel.js b/js/src/carousel.js index 87366051903f..a5ad02541a20 100644 --- a/js/src/carousel.js +++ b/js/src/carousel.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Carousel = (($) => { +const Carousel = (() => { /** diff --git a/js/src/collapse.js b/js/src/collapse.js index 7d1ba4c54fc3..acc959d40c83 100644 --- a/js/src/collapse.js +++ b/js/src/collapse.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Collapse = (($) => { +const Collapse = (() => { /** diff --git a/js/src/dropdown.js b/js/src/dropdown.js index e1c48ac6e5a4..adb54f0f2138 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -1,5 +1,5 @@ -/* global Popper */ - +import $ from 'jquery' +import Popper from 'popper.js' import Util from './util' @@ -10,7 +10,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Dropdown = (($) => { +const Dropdown = (() => { /** * Check for Popper dependency @@ -445,6 +445,6 @@ const Dropdown = (($) => { return Dropdown -})(jQuery) +})(jQuery, Popper) export default Dropdown diff --git a/js/src/index.js b/js/src/index.js new file mode 100644 index 000000000000..a3858dd24b48 --- /dev/null +++ b/js/src/index.js @@ -0,0 +1,46 @@ +import $ from 'jquery' +import Alert from './alert' +import Button from './button' +import Carousel from './carousel' +import Collapse from './collapse' +import Dropdown from './dropdown' +import Modal from './modal' +import Popover from './popover' +import Scrollspy from './scrollspy' +import Tab from './tab' +import Tooltip from './tooltip' +import Util from './util' + +/** + * -------------------------------------------------------------------------- + * Bootstrap (v4.0.0-alpha.6): index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * -------------------------------------------------------------------------- + */ + +if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.') +} + +(() => { + const version = $.fn.jquery.split(' ')[0].split('.') + const min = 3 + const max = 4 + if (version[0] < min || version[0] >= max) { + throw new Error('Bootstrap\'s JavaScript requires at least jQuery v3.0.0 but less than v4.0.0') + } +})(jQuery) + +export { + Util, + Alert, + Button, + Carousel, + Collapse, + Dropdown, + Modal, + Popover, + Scrollspy, + Tab, + Tooltip +} diff --git a/js/src/modal.js b/js/src/modal.js index ab73230c8f7f..2ff93342d5a6 100644 --- a/js/src/modal.js +++ b/js/src/modal.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Modal = (($) => { +const Modal = (() => { /** diff --git a/js/src/popover.js b/js/src/popover.js index f5820ecbed9b..aeccdf7501ab 100644 --- a/js/src/popover.js +++ b/js/src/popover.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Tooltip from './tooltip' @@ -8,7 +9,7 @@ import Tooltip from './tooltip' * -------------------------------------------------------------------------- */ -const Popover = (($) => { +const Popover = (() => { /** diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index 588f65298868..70067c0b35be 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const ScrollSpy = (($) => { +const ScrollSpy = (() => { /** diff --git a/js/src/tab.js b/js/src/tab.js index c32cd3776fff..18af4e7e27cf 100644 --- a/js/src/tab.js +++ b/js/src/tab.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import Util from './util' @@ -8,7 +9,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Tab = (($) => { +const Tab = (() => { /** diff --git a/js/src/tooltip.js b/js/src/tooltip.js index 37573cf49852..5dc28ab7ef3d 100644 --- a/js/src/tooltip.js +++ b/js/src/tooltip.js @@ -1,5 +1,5 @@ -/* global Popper */ - +import $ from 'jquery' +import Popper from 'popper.js' import Util from './util' @@ -10,7 +10,7 @@ import Util from './util' * -------------------------------------------------------------------------- */ -const Tooltip = (($) => { +const Tooltip = (() => { /** * Check for Popper dependency @@ -728,6 +728,6 @@ const Tooltip = (($) => { return Tooltip -})(jQuery) +})(jQuery, Popper) export default Tooltip diff --git a/js/src/util.js b/js/src/util.js index cd3f1fb6a206..b18d0f776d5c 100644 --- a/js/src/util.js +++ b/js/src/util.js @@ -1,3 +1,5 @@ +import $ from 'jquery' + /** * -------------------------------------------------------------------------- * Bootstrap (v4.0.0-beta): util.js @@ -5,7 +7,7 @@ * -------------------------------------------------------------------------- */ -const Util = (($) => { +const Util = (() => { /** diff --git a/js/tests/.eslintrc.json b/js/tests/.eslintrc.json index a05a3a3900fa..b039801444fd 100644 --- a/js/tests/.eslintrc.json +++ b/js/tests/.eslintrc.json @@ -28,6 +28,7 @@ "global-require": "off", "no-process-env": "off", "no-process-exit": "off", + "no-sync": "off", // Stylistic Issues "brace-style": "off", diff --git a/package-lock.json b/package-lock.json index 87ecfd220432..ce5b579a31f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -513,6 +513,15 @@ "babel-runtime": "6.26.0" } }, + "babel-plugin-external-helpers": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz", + "integrity": "sha1-IoX0iwK9Xe3oUXXK+MYuhq3M76E=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, "babel-plugin-transform-es2015-arrow-functions": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", @@ -963,6 +972,15 @@ "repeat-element": "1.1.2" } }, + "browser-resolve": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", + "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "dev": true, + "requires": { + "resolve": "1.1.7" + } + }, "browserslist": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.3.3.tgz", @@ -1714,6 +1732,12 @@ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "dev": true }, + "estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", @@ -2987,6 +3011,12 @@ "is-extglob": "1.0.0" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, "is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", @@ -4429,6 +4459,12 @@ "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=", "dev": true }, + "popper.js": { + "version": "1.12.5", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.12.5.tgz", + "integrity": "sha512-6R2eXIy1xYukMNutoD+y/Gj0IpjEQhivyZonm5Vz0Fp8jdc7kvheKCvpM/t+PxqKb7VbLVnvPVEdTyslEb7f6w==", + "dev": true + }, "postcss": { "version": "6.0.9", "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.9.tgz", @@ -5238,6 +5274,43 @@ "glob": "7.1.2" } }, + "rollup": { + "version": "0.49.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.49.2.tgz", + "integrity": "sha512-9mySqItSwq5/dXYQyFGrrzqV282EZfz4kSCU2m4e6OjgqLmIsp9zK6qNQ6wbBWR4EhASEqQMBQ/IF45jaNPAtw==", + "dev": true + }, + "rollup-plugin-babel": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-3.0.2.tgz", + "integrity": "sha512-ALGPBFtwJZcYHsNPM6RGJlEncTzAARPvZOGjNPZgDe5hS5t6sJGjiOWibEFVEz5LQN7S7spvCBILaS4N1Cql2w==", + "dev": true, + "requires": { + "rollup-pluginutils": "1.5.2" + } + }, + "rollup-plugin-node-resolve": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.0.0.tgz", + "integrity": "sha1-i4l8TDAw1QASd7BRSyXSygloPuA=", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "builtin-modules": "1.1.1", + "is-module": "1.0.0", + "resolve": "1.1.7" + } + }, + "rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "requires": { + "estree-walker": "0.2.1", + "minimatch": "3.0.4" + } + }, "run-async": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", diff --git a/package.json b/package.json index 6400999460cf..6ae3476d1507 100644 --- a/package.json +++ b/package.json @@ -33,9 +33,13 @@ "js-lint": "eslint js/ && eslint --config js/tests/.eslintrc.json --env node build/ Gruntfile.js", "js-lint-docs": "eslint --config js/tests/.eslintrc.json assets/js/ sw.js", "js-compile": "npm-run-all --parallel js-compile-*", - "js-compile-bundle": "shx cat js/src/util.js js/src/alert.js js/src/button.js js/src/carousel.js js/src/collapse.js js/src/dropdown.js js/src/modal.js js/src/scrollspy.js js/src/tab.js js/src/tooltip.js js/src/popover.js | shx sed \"s/^(import|export).*//\" | babel --filename js/src/bootstrap.js | node build/stamp.js > dist/js/bootstrap.js", - "js-compile-plugins": "babel js/src/ --out-dir js/dist/ --source-maps", - "js-minify": "uglifyjs --config-file build/uglifyjs.config.json --output dist/js/bootstrap.min.js dist/js/bootstrap.js", + "js-compile-standalone": "rollup --environment BUNDLE:false --config build/rollup.config.js", + "js-compile-bundle": "rollup --environment BUNDLE:true --config build/rollup.config.js", + "js-compile-plugins": "babel --no-babelrc js/src/ --out-dir js/dist/ --source-maps --presets=es2015 --plugins=transform-es2015-modules-strip", + "postjs-compile": "node build/stamp.js", + "js-minify": "npm-run-all --parallel js-minify-*", + "js-minify-standalone": "uglifyjs --config-file build/uglifyjs.config.json --output dist/js/bootstrap.min.js dist/js/bootstrap.js", + "js-minify-bundle": "uglifyjs --config-file build/uglifyjs.config.json --output dist/js/bootstrap.bundle.min.js dist/js/bootstrap.bundle.js", "js-minify-docs": "uglifyjs --config-file build/uglifyjs.config.json --output assets/js/docs.min.js assets/js/vendor/anchor.min.js assets/js/vendor/clipboard.min.js assets/js/vendor/holder.min.js assets/js/src/application.js assets/js/src/pwa.js", "js-test": "phantomjs ./node_modules/qunit-phantomjs-runner/runner.js js/tests/index.html 60", "js-test-cloud": "ruby -r webrick -e \"s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd, :Logger => WEBrick::Log.new('/dev/null'), :AccessLog => []); trap('INT') { s.shutdown }; s.start\" & grunt saucelabs-qunit", @@ -74,6 +78,7 @@ "autoprefixer": "^7.1.2", "babel-cli": "^6.24.1", "babel-eslint": "^7.2.3", + "babel-plugin-external-helpers": "^6.22.0", "babel-plugin-transform-es2015-modules-strip": "^0.1.1", "babel-preset-es2015": "^6.24.1", "clean-css-cli": "^4.1.6", @@ -86,9 +91,13 @@ "nodemon": "^1.11.0", "npm-run-all": "^4.0.2", "phantomjs-prebuilt": "^2.1.14", + "popper.js": "^1.12.5", "postcss-cli": "^4.1.0", "qunit-phantomjs-runner": "^2.3.0", "qunitjs": "^2.4.0", + "rollup": "^0.49.2", + "rollup-plugin-babel": "^3.0.2", + "rollup-plugin-node-resolve": "^3.0.0", "shelljs": "^0.7.8", "shx": "^0.2.2", "uglify-js": "^3.0.24"