@@ -10,5 +10,8 @@
|
||||
"jquery": true,
|
||||
"node": true
|
||||
},
|
||||
"parser": "babel-eslint"
|
||||
"rules": {
|
||||
"react/require-extension": 0,
|
||||
"import/extensions": [1, { "js": "never" }]
|
||||
}
|
||||
}
|
||||
|
||||
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,3 +1,16 @@
|
||||
### 9.0.0-alpha.4: November 16th, 2016
|
||||
* Use new webpack api schema ([8ac5f15](https://github.com/roots/sage/commit/e6e60aa))
|
||||
* Update dependencies ([70ebba7](https://github.com/roots/sage/commit/70ebba7))
|
||||
* Variables organization ([8ac5f15](https://github.com/roots/sage/commit/8ac5f15))
|
||||
* Use $.fn.ready() (reverts 724d550) ([e7fccbe](https://github.com/roots/sage/commit/e7fccbe))
|
||||
* Theme activation updates 'stylesheet' option instead of 'template' ([fb19145](https://github.com/roots/sage/commit/fb19145))
|
||||
* Reorganize and refactor build routine ([8c9ba05](https://github.com/roots/sage/commit/8c9ba05))
|
||||
* Switch assets manifest plugin ([c1bb2b3](https://github.com/roots/sage/commit/c1bb2b3))
|
||||
* Add images to assets manifest ([c49793c](https://github.com/roots/sage/commit/c49793c))
|
||||
* Switch from babel to buble ([0d38ab8](https://github.com/roots/sage/commit/0d38ab8))
|
||||
* Update dependencies & webpack compatibility (BREAKING CHANGES) ([eae52fd](https://github.com/roots/sage/commit/eae52fd))
|
||||
* Use http by default (not https) to be consistent with Trellis ([e6f2f49](https://github.com/roots/sage/commit/e6f2f49))
|
||||
|
||||
### 9.0.0-alpha.3: September 11th, 2016
|
||||
* Fix webpack HMR ([#1713](https://github.com/roots/sage/issues/1713))
|
||||
* Remove minor edits from CHANGELOG.md ([3516629](https://github.com/roots/sage/commit/3516629))
|
||||
@@ -53,6 +66,11 @@
|
||||
* Rename interfaces, unset after unwrapping ([97906e9](https://github.com/roots/sage/commit/97906e9))
|
||||
* Restructure theme, use autoloader ([9eaffa3](https://github.com/roots/sage/commit/9eaffa3a2d4df462dd8020a10551334208bd32a3))
|
||||
|
||||
### 8.5.0: September 20th, 2016
|
||||
* Update installation instructions
|
||||
* Update dependencies
|
||||
* Update to Bootstrap 4.0.0-alpha.4 ([5eb01fd](https://github.com/roots/sage/commit/5eb01fd0319a7b6576e31579dc50e16b023abb74))
|
||||
|
||||
### 8.4.2: February 19th, 2016
|
||||
* Add Composer vendor directory to gitignore ([#1618](https://github.com/roots/sage/issues/1618))
|
||||
* Fix build test by removing trailing space ([#1617](https://github.com/roots/sage/issues/1617))
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
"extends": "airbnb",
|
||||
"rules": {
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"prefer-rest-params": 0
|
||||
"prefer-rest-params": 0,
|
||||
"react/require-extension": 0,
|
||||
"import/extensions": [1, { "js": "never" }]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
const path = require('path');
|
||||
const argv = require('minimist')(process.argv.slice(2));
|
||||
const glob = require('glob-all');
|
||||
const merge = require('lodash/merge');
|
||||
const uniq = require('lodash/uniq');
|
||||
|
||||
const mergeWithConcat = require('./util/mergeWithConcat');
|
||||
const userConfig = require('../config');
|
||||
@@ -12,7 +11,7 @@ const rootPath = (userConfig.paths && userConfig.paths.root)
|
||||
: process.cwd();
|
||||
|
||||
const config = mergeWithConcat({
|
||||
copy: ['images/**/*'],
|
||||
copy: 'images/**/*',
|
||||
proxyUrl: 'http://localhost:3000',
|
||||
cacheBusting: '[name]_[hash]',
|
||||
paths: {
|
||||
@@ -22,27 +21,22 @@ const config = mergeWithConcat({
|
||||
},
|
||||
enabled: {
|
||||
sourceMaps: !isProduction,
|
||||
minify: isProduction,
|
||||
optimize: isProduction,
|
||||
cacheBusting: isProduction,
|
||||
watcher: !!argv.watch,
|
||||
uglifyJs: !(argv.p || argv.optimizeMinimize),
|
||||
},
|
||||
watch: [],
|
||||
}, userConfig);
|
||||
|
||||
config.watch.push(`${path.basename(config.paths.assets)}/${config.copy}`);
|
||||
config.watch = uniq(config.watch);
|
||||
|
||||
Object.keys(config.entry).forEach(id =>
|
||||
config.entry[id].unshift(path.join(__dirname, 'public-path.js')));
|
||||
|
||||
module.exports = mergeWithConcat(config, {
|
||||
env: merge({ production: isProduction, development: !isProduction }, argv.env),
|
||||
entry: {
|
||||
get files() {
|
||||
return glob.sync(config.copy, {
|
||||
cwd: config.paths.assets,
|
||||
mark: true,
|
||||
}).filter(file => !((file.slice(-1) === '/') || (!file.indexOf('*') === -1)))
|
||||
.map(file => path.join(config.paths.assets, file));
|
||||
},
|
||||
},
|
||||
env: Object.assign({ production: isProduction, development: !isProduction }, argv.env),
|
||||
publicPath: `${config.publicPath}/${path.basename(config.paths.dist)}/`,
|
||||
manifest: {},
|
||||
});
|
||||
|
||||
|
||||
34
assets/build/util/assetManifestsFormatter.js
Normal file
34
assets/build/util/assetManifestsFormatter.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = (key, value) => {
|
||||
if (typeof value === 'string') {
|
||||
return value;
|
||||
}
|
||||
const manifest = value;
|
||||
/**
|
||||
* Hack to prepend scripts/ or styles/ to manifest keys
|
||||
*
|
||||
* This might need to be reworked at some point.
|
||||
*
|
||||
* Before:
|
||||
* {
|
||||
* "main.js": "scripts/main_abcdef.js"
|
||||
* "main.css": "styles/main_abcdef.css"
|
||||
* }
|
||||
* After:
|
||||
* {
|
||||
* "scripts/main.js": "scripts/main_abcdef.js"
|
||||
* "styles/main.css": "styles/main_abcdef.css"
|
||||
* }
|
||||
*/
|
||||
Object.keys(manifest).forEach((src) => {
|
||||
const sourcePath = path.basename(path.dirname(src));
|
||||
const targetPath = path.basename(path.dirname(manifest[src]));
|
||||
if (sourcePath === targetPath) {
|
||||
return;
|
||||
}
|
||||
manifest[`${targetPath}/${src}`] = manifest[src];
|
||||
delete manifest[src];
|
||||
});
|
||||
return manifest;
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Process AssetsPlugin output and format it
|
||||
* for Sage: {"[name].[ext]":"[name]_[hash].[ext]"}
|
||||
* @param {Object} assets passed by processOutput
|
||||
* @return {String} JSON
|
||||
*/
|
||||
module.exports = (assets) => {
|
||||
const results = {};
|
||||
Object.keys(assets).forEach((name) => {
|
||||
Object.keys(assets[name]).forEach((ext) => {
|
||||
const filename = `${path.dirname(assets[name][ext])}/${path.basename(`${name}.${ext}`)}`;
|
||||
results[filename] = assets[name][ext];
|
||||
});
|
||||
});
|
||||
return JSON.stringify(results);
|
||||
};
|
||||
50
assets/build/util/interpolateName.js
Normal file
50
assets/build/util/interpolateName.js
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const path = require('path');
|
||||
const utils = require('loader-utils');
|
||||
|
||||
/**
|
||||
* Generate output name from output pattern
|
||||
*
|
||||
* @link https://github.com/kevlened/copy-webpack-plugin/blob/323b1d74ef35ed2221637d8028b1bef854deb523/src/writeFile.js#L31-L65
|
||||
* @param {string} pattern
|
||||
* @param {string} relativeFrom
|
||||
* @param {binary} content
|
||||
* @return {string}
|
||||
*/
|
||||
module.exports = (pattern, relativeFrom, content) => {
|
||||
let webpackTo = pattern;
|
||||
let resourcePath = relativeFrom;
|
||||
|
||||
/* A hack so .dotted files don't get parsed as extensions */
|
||||
const basename = path.basename(resourcePath);
|
||||
let dotRemoved = false;
|
||||
if (basename[0] === '.') {
|
||||
dotRemoved = true;
|
||||
resourcePath = path.join(path.dirname(resourcePath), basename.slice(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* If it doesn't have an extension, remove it from the pattern
|
||||
* ie. [name].[ext] or [name][ext] both become [name]
|
||||
*/
|
||||
if (!path.extname(resourcePath)) {
|
||||
webpackTo = webpackTo.replace(/\.?\[ext]/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* A hack because loaderUtils.interpolateName doesn't
|
||||
* find the right path if no directory is defined
|
||||
* ie. [path] applied to 'file.txt' would return 'file'
|
||||
*/
|
||||
if (resourcePath.indexOf('/') < 0) {
|
||||
resourcePath = `/${resourcePath}`;
|
||||
}
|
||||
|
||||
webpackTo = utils.interpolateName({ resourcePath }, webpackTo, { content });
|
||||
|
||||
if (dotRemoved) {
|
||||
webpackTo = path.join(path.dirname(webpackTo), `.${path.basename(webpackTo)}`);
|
||||
}
|
||||
return webpackTo;
|
||||
};
|
||||
21
assets/build/util/promisify.js
Normal file
21
assets/build/util/promisify.js
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Node-style asynchronous function.
|
||||
*
|
||||
* @callback nodeAsyncCallback
|
||||
* @param {string|null} err
|
||||
* @param {*} data
|
||||
*/
|
||||
/**
|
||||
* Promisify node-style asynchronous functions
|
||||
*
|
||||
* @param {nodeAsyncCallback} fn - Function with node-style callback
|
||||
* @param {this} [scope] - Scope to which the function should be bound. Default: fn
|
||||
* @returns {Promise} - An instance of Promise
|
||||
*/
|
||||
module.exports = (fn, scope) => function callback() {
|
||||
const args = [].slice.call(arguments);
|
||||
return new Promise((resolve, reject) => {
|
||||
args.push((err, data) => (err === null ? resolve(data) : reject(err)));
|
||||
return fn.apply(scope || fn, args);
|
||||
});
|
||||
};
|
||||
@@ -1,16 +1,13 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const qs = require('qs');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const CleanPlugin = require('clean-webpack-plugin');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const ImageminPlugin = require('imagemin-webpack-plugin').default;
|
||||
const imageminMozjpeg = require('imagemin-mozjpeg');
|
||||
|
||||
const CopyGlobsPlugin = require('./webpack.plugin.copyglobs');
|
||||
const mergeWithConcat = require('./util/mergeWithConcat');
|
||||
const addHotMiddleware = require('./util/addHotMiddleware');
|
||||
const webpackConfigProduction = require('./webpack.config.production');
|
||||
const webpackConfigWatch = require('./webpack.config.watch');
|
||||
const config = require('./config');
|
||||
|
||||
const assetsFilenames = (config.enabled.cacheBusting) ? config.cacheBusting : '[name]';
|
||||
@@ -19,20 +16,17 @@ const sourceMapQueryStr = (config.enabled.sourceMaps) ? '+sourceMap' : '-sourceM
|
||||
const jsLoader = {
|
||||
test: /\.js$/,
|
||||
exclude: [/(node_modules|bower_components)(?)/],
|
||||
loaders: [{
|
||||
loader: 'babel',
|
||||
query: {
|
||||
presets: [[path.resolve('./node_modules/babel-preset-es2015'), { modules: false }]],
|
||||
cacheDirectory: true,
|
||||
},
|
||||
use: [{
|
||||
loader: 'buble',
|
||||
options: { objectAssign: 'Object.assign' },
|
||||
}],
|
||||
};
|
||||
|
||||
if (config.enabled.watcher) {
|
||||
jsLoader.loaders.unshift('monkey-hot?sourceType=module');
|
||||
jsLoader.use.unshift('monkey-hot?sourceType=module');
|
||||
}
|
||||
|
||||
const webpackConfig = {
|
||||
let webpackConfig = {
|
||||
context: config.paths.assets,
|
||||
entry: config.entry,
|
||||
devtool: (config.enabled.sourceMaps ? '#source-map' : undefined),
|
||||
@@ -42,15 +36,14 @@ const webpackConfig = {
|
||||
filename: `scripts/${assetsFilenames}.js`,
|
||||
},
|
||||
module: {
|
||||
preLoaders: [
|
||||
rules: [
|
||||
jsLoader,
|
||||
{
|
||||
enforce: 'pre',
|
||||
test: /\.js?$/,
|
||||
include: config.paths.assets,
|
||||
loader: 'eslint',
|
||||
},
|
||||
],
|
||||
loaders: [
|
||||
jsLoader,
|
||||
{
|
||||
test: /\.css$/,
|
||||
include: config.paths.assets,
|
||||
@@ -78,9 +71,9 @@ const webpackConfig = {
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg|ico)$/,
|
||||
include: config.paths.assets,
|
||||
loaders: [
|
||||
use: [
|
||||
`file?${qs.stringify({
|
||||
name: '[path][name].[ext]',
|
||||
name: `[path]${assetsFilenames}.[ext]`,
|
||||
})}`,
|
||||
],
|
||||
},
|
||||
@@ -104,43 +97,37 @@ const webpackConfig = {
|
||||
test: /\.(ttf|eot|woff2?|png|jpe?g|gif|svg)$/,
|
||||
include: /node_modules|bower_components/,
|
||||
loader: 'file',
|
||||
query: {
|
||||
options: {
|
||||
name: `vendor/${config.cacheBusting}.[ext]`,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
modules: [
|
||||
config.paths.assets,
|
||||
'node_modules',
|
||||
'bower_components',
|
||||
],
|
||||
enforceExtensions: false,
|
||||
resolve: {
|
||||
modules: [
|
||||
config.paths.assets,
|
||||
'node_modules',
|
||||
'bower_components',
|
||||
],
|
||||
enforceExtension: false,
|
||||
},
|
||||
resolveLoader: {
|
||||
moduleExtensions: ['-loader'],
|
||||
},
|
||||
externals: {
|
||||
jquery: 'jQuery',
|
||||
},
|
||||
plugins: [
|
||||
new CleanPlugin([config.paths.dist], config.paths.root),
|
||||
new ImageminPlugin({
|
||||
optipng: {
|
||||
optimizationLevel: 7,
|
||||
},
|
||||
gifsicle: {
|
||||
optimizationLevel: 3,
|
||||
},
|
||||
pngquant: {
|
||||
quality: '65-90',
|
||||
speed: 4,
|
||||
},
|
||||
svgo: {
|
||||
removeUnknownsAndDefaults: false,
|
||||
cleanupIDs: false,
|
||||
},
|
||||
jpegtran: null,
|
||||
plugins: [imageminMozjpeg({
|
||||
quality: 75,
|
||||
})],
|
||||
disable: (config.enabled.watcher),
|
||||
new CleanPlugin([config.paths.dist], {
|
||||
root: config.paths.root,
|
||||
verbose: false,
|
||||
}),
|
||||
new CopyGlobsPlugin({
|
||||
// It would be nice to switch to copy-webpack-plugin, but unfortunately it doesn't
|
||||
// provide a reliable way of tracking the before/after file names
|
||||
pattern: config.copy,
|
||||
output: `[path]${assetsFilenames}.[ext]`,
|
||||
manifest: config.manifest,
|
||||
}),
|
||||
new ExtractTextPlugin({
|
||||
filename: `styles/${assetsFilenames}.css`,
|
||||
@@ -160,42 +147,56 @@ const webpackConfig = {
|
||||
: false,
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: config.enabled.minify,
|
||||
minimize: config.enabled.optimize,
|
||||
debug: config.enabled.watcher,
|
||||
stats: { colors: true },
|
||||
postcss: [
|
||||
autoprefixer({
|
||||
browsers: [
|
||||
'last 2 versions',
|
||||
'android 4',
|
||||
'opera 12',
|
||||
],
|
||||
}),
|
||||
],
|
||||
eslint: {
|
||||
failOnWarning: false,
|
||||
failOnError: true,
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
test: /\.s?css$/,
|
||||
options: {
|
||||
output: { path: config.paths.dist },
|
||||
context: config.paths.assets,
|
||||
postcss: [
|
||||
autoprefixer({ browsers: ['last 2 versions', 'android 4', 'opera 12'] }),
|
||||
],
|
||||
},
|
||||
}),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
test: /\.js$/,
|
||||
options: {
|
||||
eslint: { failOnWarning: false, failOnError: true },
|
||||
},
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = webpackConfig;
|
||||
/* eslint-disable global-require */ /** Let's only load dependencies as needed */
|
||||
|
||||
if (config.env.optimize) {
|
||||
webpackConfig = mergeWithConcat(webpackConfig, require('./webpack.config.optimize'));
|
||||
}
|
||||
|
||||
if (config.env.production) {
|
||||
module.exports = mergeWithConcat(webpackConfig, webpackConfigProduction);
|
||||
webpackConfig.plugins.push(new webpack.NoErrorsPlugin());
|
||||
}
|
||||
|
||||
if (config.enabled.watcher) {
|
||||
module.exports = mergeWithConcat(webpackConfig, webpackConfigWatch, {
|
||||
entry: addHotMiddleware(webpackConfig.entry),
|
||||
});
|
||||
}
|
||||
if (config.enabled.cacheBusting) {
|
||||
const WebpackAssetsManifest = require('webpack-assets-manifest');
|
||||
|
||||
if (config.enabled.uglifyJs) {
|
||||
module.exports.plugins.push(
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: config.enabled.sourceMaps,
|
||||
webpackConfig.plugins.push(
|
||||
new WebpackAssetsManifest({
|
||||
output: 'assets.json',
|
||||
space: 2,
|
||||
writeToDisk: false,
|
||||
assets: config.manifest,
|
||||
replacer: require('./util/assetManifestsFormatter'),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (config.enabled.watcher) {
|
||||
webpackConfig.entry = require('./util/addHotMiddleware')(webpackConfig.entry);
|
||||
webpackConfig = mergeWithConcat(webpackConfig, require('./webpack.config.watch'));
|
||||
}
|
||||
|
||||
module.exports = webpackConfig;
|
||||
|
||||
26
assets/build/webpack.config.optimize.js
Normal file
26
assets/build/webpack.config.optimize.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const ImageminPlugin = require('imagemin-webpack-plugin').default;
|
||||
const imageminMozjpeg = require('imagemin-mozjpeg');
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
const config = require('./config');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
new OptimizeCssAssetsPlugin({
|
||||
cssProcessor: cssnano,
|
||||
cssProcessorOptions: { discardComments: { removeAll: true } },
|
||||
canPrint: true,
|
||||
}),
|
||||
new ImageminPlugin({
|
||||
optipng: { optimizationLevel: 7 },
|
||||
gifsicle: { optimizationLevel: 3 },
|
||||
pngquant: { quality: '65-90', speed: 4 },
|
||||
svgo: { removeUnknownsAndDefaults: false, cleanupIDs: false },
|
||||
plugins: [imageminMozjpeg({ quality: 75 })],
|
||||
disable: (config.enabled.watcher),
|
||||
}),
|
||||
],
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
const AssetsPlugin = require('assets-webpack-plugin');
|
||||
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
const processOutput = require('./util/assetsPluginProcessOutput');
|
||||
const config = require('./config');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
new AssetsPlugin({
|
||||
path: config.paths.dist,
|
||||
filename: 'assets.json',
|
||||
fullPath: false,
|
||||
processOutput,
|
||||
}),
|
||||
new OptimizeCssAssetsPlugin({
|
||||
cssProcessor: cssnano,
|
||||
cssProcessorOptions: { discardComments: { removeAll: true } },
|
||||
canPrint: true,
|
||||
}),
|
||||
],
|
||||
};
|
||||
@@ -1,13 +1,12 @@
|
||||
const webpack = require('webpack');
|
||||
const BrowserSyncPlugin = require('./webpack.plugin.browsersync');
|
||||
const mergeWithConcat = require('./util/mergeWithConcat');
|
||||
|
||||
const config = require('./config');
|
||||
|
||||
module.exports = {
|
||||
output: { pathinfo: true },
|
||||
debug: true,
|
||||
devtool: '#cheap-module-source-map',
|
||||
stats: false,
|
||||
plugins: [
|
||||
new webpack.optimize.OccurrenceOrderPlugin(),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
@@ -16,9 +15,7 @@ module.exports = {
|
||||
target: config.devUrl,
|
||||
publicPath: config.publicPath,
|
||||
proxyUrl: config.proxyUrl,
|
||||
browserSyncOptions: mergeWithConcat({
|
||||
files: config.watch,
|
||||
}, config.browserSyncOptions),
|
||||
watch: config.watch,
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
'use strict'; // eslint-disable-line strict
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||
const browserSync = require('browser-sync');
|
||||
const url = require('url');
|
||||
const uniq = require('lodash/uniq');
|
||||
|
||||
const mergeWithConcat = require('./util/mergeWithConcat');
|
||||
|
||||
@@ -13,6 +14,7 @@ module.exports = class {
|
||||
this.compiler = null;
|
||||
this.options = mergeWithConcat({
|
||||
proxyUrl: 'https://localhost:3000',
|
||||
watch: [],
|
||||
callback() {},
|
||||
}, options);
|
||||
}
|
||||
@@ -27,7 +29,9 @@ module.exports = class {
|
||||
compiler.plugin('compilation', () => this.watcher.notify('Rebuilding...'));
|
||||
this.start();
|
||||
}
|
||||
// Optionally add logic for this.watcher.reload()
|
||||
/* You may optionally add custom logic here to trigger either of the following */
|
||||
// this.watcher.reload()
|
||||
// this.watcher.reload({ stream: true })
|
||||
});
|
||||
}
|
||||
start() {
|
||||
@@ -38,13 +42,16 @@ module.exports = class {
|
||||
target: this.options.target,
|
||||
middleware: this.middleware(),
|
||||
},
|
||||
files: [],
|
||||
}, this.options.browserSyncOptions);
|
||||
watcherConfig.files = uniq(watcherConfig.files.concat(this.options.watch));
|
||||
this.watcher.init(watcherConfig, this.options.callback.bind(this));
|
||||
}
|
||||
middleware() {
|
||||
this.webpackDevMiddleware = webpackDevMiddleware(this.compiler, {
|
||||
publicPath: this.options.publicPath,
|
||||
stats: { colors: true },
|
||||
stats: false,
|
||||
noInfo: true,
|
||||
});
|
||||
this.webpackHotMiddleware = webpackHotMiddleware(this.compiler, {
|
||||
log: this.watcher.notify.bind(this.watcher),
|
||||
|
||||
143
assets/build/webpack.plugin.copyglobs.js
Normal file
143
assets/build/webpack.plugin.copyglobs.js
Normal file
@@ -0,0 +1,143 @@
|
||||
'use strict'; // eslint-disable-line
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const utils = require('loader-utils');
|
||||
const includes = require('lodash/includes');
|
||||
|
||||
const interpolateName = require('./util/interpolateName');
|
||||
const promisify = require('./util/promisify');
|
||||
|
||||
const fixPath = v => v.replace(/\\/g, '/');
|
||||
const errorMsg = msg => `\x1b[31m${msg}\x1b[0m`;
|
||||
|
||||
const GLOB_CWD_AUTO = null;
|
||||
|
||||
const globAsync = promisify(glob);
|
||||
const statAsync = promisify(fs.stat);
|
||||
const readFileAsync = promisify(fs.readFile);
|
||||
|
||||
class PatternUndefinedError extends Error {
|
||||
constructor() {
|
||||
super(errorMsg('[copy-globs] You must provide glob pattern.'));
|
||||
}
|
||||
}
|
||||
|
||||
class ArgsArrayError extends TypeError {
|
||||
constructor() {
|
||||
super(errorMsg(
|
||||
'[copy-globs] pattern cannot be an array.\n' +
|
||||
'For multiple folders, use something like:\n\n' +
|
||||
' +(images|fonts)/**/*\n\n' +
|
||||
'See also: https://github.com/isaacs/node-glob#glob-primer\n'
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error if pattern is an array or undefined
|
||||
*
|
||||
* @param pattern
|
||||
*/
|
||||
const testPattern = (pattern) => {
|
||||
if (pattern === undefined) {
|
||||
throw new PatternUndefinedError();
|
||||
}
|
||||
if (Array.isArray(pattern)) {
|
||||
throw new ArgsArrayError();
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeArguments = (input) => {
|
||||
testPattern(input);
|
||||
const options = {};
|
||||
if (typeof input === 'string') {
|
||||
options.pattern = input;
|
||||
} else {
|
||||
testPattern(input.pattern);
|
||||
return input;
|
||||
}
|
||||
return options;
|
||||
};
|
||||
|
||||
module.exports = class {
|
||||
constructor(o) {
|
||||
const options = normalizeArguments(o);
|
||||
this.pattern = options.pattern;
|
||||
this.disable = options.disable;
|
||||
this.output = options.output || '[path][name].[ext]';
|
||||
this.globOptions = Object.assign(options.globOptions || {}, { cwd: GLOB_CWD_AUTO });
|
||||
this.globOptions.nodir = true;
|
||||
this.manifest = options.manifest || {};
|
||||
this.files = [];
|
||||
}
|
||||
apply(compiler) {
|
||||
if (this.disable) {
|
||||
return;
|
||||
}
|
||||
this.compiler = compiler;
|
||||
this.resolveWorkingDirectory();
|
||||
compiler.plugin('emit', this.emitHandler.bind(this));
|
||||
compiler.plugin('after-emit', this.afterEmitHandler.bind(this));
|
||||
}
|
||||
emitHandler(compilation, callback) {
|
||||
this.compilation = compilation;
|
||||
globAsync(this.pattern, this.globOptions)
|
||||
.then(
|
||||
paths => Promise.all(paths.map(this.processAsset.bind(this))),
|
||||
err => compilation.errors.push(err)
|
||||
)
|
||||
.then(() => {
|
||||
Object.keys(this.files).forEach((absoluteFrom) => {
|
||||
const file = this.files[absoluteFrom];
|
||||
this.manifest[file.relativeFrom] = file.webpackTo;
|
||||
this.compilation.assets[file.webpackTo] = {
|
||||
size: () => file.stat.size,
|
||||
source: () => file.content,
|
||||
};
|
||||
});
|
||||
})
|
||||
.then(callback);
|
||||
}
|
||||
afterEmitHandler(compilation, callback) {
|
||||
Object.keys(this.files)
|
||||
.filter(absoluteFrom => !includes(compilation.fileDependencies, absoluteFrom))
|
||||
.forEach(absoluteFrom => compilation.fileDependencies.push(absoluteFrom));
|
||||
callback();
|
||||
}
|
||||
resolveWorkingDirectory() {
|
||||
if (this.globOptions.cwd === GLOB_CWD_AUTO) {
|
||||
this.globOptions.cwd = this.compiler.options.context;
|
||||
}
|
||||
this.context = this.globOptions.cwd || this.compiler.options.context;
|
||||
}
|
||||
processAsset(relativeFrom) {
|
||||
if (this.compilation.assets[relativeFrom]) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const absoluteFrom = path.resolve(this.context, relativeFrom);
|
||||
return statAsync(absoluteFrom)
|
||||
.then(stat => this.buildFileObject(relativeFrom, absoluteFrom, stat))
|
||||
.then(this.addAsset.bind(this));
|
||||
}
|
||||
buildFileObject(relativeFrom, absoluteFrom, stat) {
|
||||
return readFileAsync(absoluteFrom)
|
||||
.then((content) => {
|
||||
const hash = utils.getHashDigest(content);
|
||||
const webpackTo = fixPath(interpolateName(this.output, relativeFrom, content));
|
||||
return { relativeFrom, absoluteFrom, stat, content, hash, webpackTo };
|
||||
});
|
||||
}
|
||||
addAsset(file) {
|
||||
const asset = this.getAsset(file.absoluteFrom);
|
||||
if (asset && asset.hash === file.hash) {
|
||||
return null;
|
||||
}
|
||||
this.files[file.absoluteFrom] = file;
|
||||
return file;
|
||||
}
|
||||
getAsset(absoluteFrom) {
|
||||
return this.files[absoluteFrom];
|
||||
}
|
||||
};
|
||||
@@ -13,7 +13,7 @@
|
||||
"src/**/*.php"
|
||||
],
|
||||
"publicPath": "/app/themes/sage",
|
||||
"devUrl": "https://example.dev",
|
||||
"proxyUrl": "https://localhost:3000",
|
||||
"devUrl": "http://example.dev",
|
||||
"proxyUrl": "http://localhost:3000",
|
||||
"cacheBusting": "[name]_[hash:8]"
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ const routes = {
|
||||
};
|
||||
|
||||
// Load Events
|
||||
document.addEventListener('DOMContentLoaded', () => new Router(routes).loadEvents());
|
||||
jQuery(document).ready(() => new Router(routes).loadEvents());
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// Grid settings
|
||||
$enable-flex: true;
|
||||
$main-sm-columns: 12;
|
||||
$sidebar-sm-columns: 4;
|
||||
|
||||
// Colors
|
||||
$brand-primary: #27ae60;
|
||||
|
||||
// Font Awesome | see: http://fontawesome.io/get-started/
|
||||
// Global options
|
||||
$enable-flex: true;
|
||||
|
||||
// Grid settings
|
||||
$main-sm-columns: 12;
|
||||
$sidebar-sm-columns: 4;
|
||||
|
||||
// Vendor variables
|
||||
$fa-font-path: '~font-awesome/fonts';
|
||||
|
||||
@@ -20,22 +20,21 @@ if (file_exists($composer = __DIR__ . '/vendor/autoload.php')) {
|
||||
* We do this so that the Template Hierarchy will look in themes/sage/templates for core WordPress themes
|
||||
* But functions.php, style.css, and index.php are all still located in themes/sage
|
||||
*
|
||||
* themes/sage/index.php also contains some self-correcting code, just in case the template option gets reset
|
||||
* get_template_directory() -> /srv/www/example.com/current/web/app/themes/sage
|
||||
* get_stylesheet_directory() -> /srv/www/example.com/current/web/app/themes/sage
|
||||
* locate_template()
|
||||
* ├── STYLESHEETPATH -> /srv/www/example.com/current/web/app/themes/sage
|
||||
* └── TEMPLATEPATH -> /srv/www/example.com/current/web/app/themes/sage/templates
|
||||
*/
|
||||
add_filter('stylesheet', function ($stylesheet) {
|
||||
add_filter('template', function ($stylesheet) {
|
||||
return dirname($stylesheet);
|
||||
});
|
||||
add_action('after_switch_theme', function () {
|
||||
$stylesheet = get_option('stylesheet');
|
||||
$stylesheet = get_option('template');
|
||||
if (basename($stylesheet) !== 'templates') {
|
||||
update_option('stylesheet', $stylesheet . '/templates');
|
||||
update_option('template', $stylesheet . '/templates');
|
||||
}
|
||||
});
|
||||
add_action('customize_render_section', function ($section) {
|
||||
if ($section->type === 'themes') {
|
||||
$section->title = wp_get_theme(basename(__DIR__))->display('Name');
|
||||
}
|
||||
}, 10, 2);
|
||||
|
||||
/**
|
||||
* Sage includes
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
<?php
|
||||
|
||||
if (defined('ABSPATH')) {
|
||||
update_option('template', get_option('template') . '/templates');
|
||||
}
|
||||
die("Kind Regards,\nRoots");
|
||||
include __DIR__ . '/templates/index.php';
|
||||
|
||||
66
package.json
66
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sage",
|
||||
"version": "9.0.0-alpha.3",
|
||||
"version": "9.0.0-alpha.4",
|
||||
"author": "Roots <team@roots.io>",
|
||||
"homepage": "https://roots.io/sage/",
|
||||
"private": true,
|
||||
@@ -19,63 +19,59 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "webpack --progress --config assets/build/webpack.config.js",
|
||||
"build:production": "npm run build -s -- -p",
|
||||
"start": "npm run build -s -- --watch",
|
||||
"build:production": "webpack --progress -p --config assets/build/webpack.config.js",
|
||||
"build:profile": "webpack --progress --profile --json --config assets/build/webpack.config.js",
|
||||
"start": "webpack --hide-modules --watch --config assets/build/webpack.config.js",
|
||||
"clean": "rimraf dist",
|
||||
"lint": "eslint assets/scripts assets/build",
|
||||
"test": "npm run lint -s"
|
||||
"test": "npm run lint"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"assets-webpack-plugin": "^3.4.0",
|
||||
"autoprefixer": "^6.4.1",
|
||||
"babel-cli": "^6.14.0",
|
||||
"babel-core": "^6.14.0",
|
||||
"babel-eslint": "^6.1.2",
|
||||
"babel-loader": "^6.2.5",
|
||||
"babel-preset-es2015": "^6.14.0",
|
||||
"babel-register": "^6.14.0",
|
||||
"babel-runtime": "^6.11.6",
|
||||
"autoprefixer": "^6.5.2",
|
||||
"body-parser": "^1.15.2",
|
||||
"browser-sync": "^2.15.0",
|
||||
"clean-webpack-plugin": "^0.1.10",
|
||||
"browser-sync": "^2.17.5",
|
||||
"buble": "^0.14.2",
|
||||
"buble-loader": "^0.3.2",
|
||||
"clean-webpack-plugin": "^0.1.13",
|
||||
"css-loader": "^0.25.0",
|
||||
"cssnano": "^3.7.4",
|
||||
"eslint": "^3.5.0",
|
||||
"eslint-config-airbnb": "^11.0.0",
|
||||
"eslint-config-airbnb-es5": "^1.0.9",
|
||||
"eslint-loader": "^1.5.0",
|
||||
"eslint-plugin-import": "^1.14.0",
|
||||
"eslint-plugin-jsx-a11y": "^2.2.1",
|
||||
"eslint-plugin-react": "^6.2.0",
|
||||
"cssnano": "^3.8.0",
|
||||
"eslint": "^3.9.1",
|
||||
"eslint-config-airbnb": "^12.0.0",
|
||||
"eslint-loader": "^1.6.1",
|
||||
"eslint-plugin-import": "^2.0.1",
|
||||
"eslint-plugin-jsx-a11y": "^2.2.3",
|
||||
"eslint-plugin-react": "^6.6.0",
|
||||
"extract-text-webpack-plugin": "^2.0.0-beta.4",
|
||||
"file-loader": "^0.9.0",
|
||||
"glob-all": "^3.1.0",
|
||||
"glob": "^7.1.1",
|
||||
"imagemin-mozjpeg": "^6.0.0",
|
||||
"imagemin-webpack-plugin": "^1.1.0",
|
||||
"imagemin-webpack-plugin": "^1.2.1",
|
||||
"imports-loader": "^0.6.5",
|
||||
"lodash": "^4.15.0",
|
||||
"loader-utils": "^0.2.16",
|
||||
"lodash": "^4.16.6",
|
||||
"minimist": "^1.2.0",
|
||||
"monkey-hot-loader": "github:rmarscher/monkey-hot-loader#webpack2-import",
|
||||
"node-sass": "^3.9.3",
|
||||
"node-sass": "^3.11.2",
|
||||
"optimize-css-assets-webpack-plugin": "^1.3.0",
|
||||
"postcss": "^5.2.0",
|
||||
"postcss-loader": "^0.13.0",
|
||||
"qs": "^6.2.1",
|
||||
"postcss": "^5.2.5",
|
||||
"postcss-loader": "^1.1.0",
|
||||
"qs": "^6.3.0",
|
||||
"resolve-url-loader": "^1.6.0",
|
||||
"rimraf": "^2.5.4",
|
||||
"sass-loader": "^4.0.2",
|
||||
"style-loader": "^0.13.1",
|
||||
"url-loader": "^0.5.7",
|
||||
"webpack": "2.1.0-beta.22",
|
||||
"webpack-dev-middleware": "^1.7.0",
|
||||
"webpack-hot-middleware": "^2.12.2"
|
||||
"webpack": "^2.1.0-beta.26",
|
||||
"webpack-assets-manifest": "^0.6.1",
|
||||
"webpack-dev-middleware": "^1.8.4",
|
||||
"webpack-hot-middleware": "^2.13.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bootstrap": "github:twbs/bootstrap#v4-dev",
|
||||
"font-awesome": "^4.6.3",
|
||||
"bootstrap": "^4.0.0-alpha.5",
|
||||
"font-awesome": "^4.7.0",
|
||||
"jquery": "1.12.4 - 3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ function template_part($template, array $context = [], $layout = 'base')
|
||||
function asset_path($filename)
|
||||
{
|
||||
static $manifest;
|
||||
isset($manifest) || $manifest = new JsonManifest(get_template_directory() . '/' . Asset::$dist . '/assets.json');
|
||||
isset($manifest) || $manifest = new JsonManifest(get_stylesheet_directory() . '/' . Asset::$dist . '/assets.json');
|
||||
return (string) new Asset($filename, $manifest);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Theme Name: Sage Starter Theme
|
||||
Theme URI: https://roots.io/sage/
|
||||
Description: Sage is a WordPress starter theme. <a href="https://github.com/roots/sage">Contribute on GitHub</a>
|
||||
Version: 9.0.0-alpha.3
|
||||
Version: 9.0.0-alpha.4
|
||||
Author: Roots
|
||||
Author URI: https://roots.io/
|
||||
Text Domain: sage
|
||||
|
||||
Reference in New Issue
Block a user