nav tabs on admin dashboard

This commit is contained in:
2019-03-07 00:20:34 -06:00
parent f73d6ae228
commit e4f473f376
11661 changed files with 216240 additions and 1544253 deletions

16
node_modules/laravel-mix/src/Api.js generated vendored
View File

@@ -1,4 +1,3 @@
let Assert = require('./Assert');
let webpack = require('webpack');
let path = require('path');
@@ -6,12 +5,19 @@ class Api {
/**
* Enable sourcemap support.
*
* @param {Boolean} productionToo
* @param {string} type
* @param {Boolean} generateForProduction
* @param {string} devType
* @param {string} productionType
*/
sourceMaps(productionToo = true, type = 'eval-source-map') {
sourceMaps(
generateForProduction = true,
devType = 'eval-source-map',
productionType = 'source-map'
) {
let type = devType;
if (Mix.inProduction()) {
type = productionToo ? 'source-map' : false;
type = generateForProduction ? productionType : false;
}
Config.sourcemaps = type;

View File

@@ -1,12 +1,25 @@
let process = require('child_process');
let File = require('../src/File');
let childProcess = require('child_process');
let File = require('./File');
let Log = require('./Log');
let argv = require('yargs').argv;
class Dependencies {
/**
* Create a new Dependencies instance.
*
* @param {Object} dependencies
*/
constructor(dependencies) {
this.dependencies = dependencies;
}
install(abortOnComplete = false) {
/**
* Install all dependencies that aren't available.
*
* @param {Boolean} abortOnComplete
* @param {Boolean} forceNpm
*/
install(abortOnComplete = false, forceNpm = false) {
this.dependencies
.reject(dependency => {
try {
@@ -17,40 +30,74 @@ class Dependencies {
})
.tap(dependencies => {
this.execute(
this.buildInstallCommand(dependencies),
this.buildInstallCommand(dependencies, forceNpm),
dependencies,
abortOnComplete
);
});
}
execute(command, abortOnComplete) {
console.log(
'Additional dependencies must be installed. ' +
'This will only take a moment.'
/**
* Execute the provided console command.
*
* @param {string} command
* @param {Boolean} abortOnComplete
*/
execute(command, dependencies, abortOnComplete) {
Log.feedback(
'Additional dependencies must be installed. This will only take a moment.'
);
process.execSync(command);
Log.feedback(`Running: ${command}`);
childProcess.execSync(command);
Log.feedback(
'Okay, done. The following packages have been installed and saved to your package.json dependencies list:'
);
dependencies.forEach(d => Log.feedback('- ' + d));
this.respond(abortOnComplete);
}
/**
* Build the dependency install command.
*
* @param {Object} dependencies
* @param {Boolean} forceNpm
*/
buildInstallCommand(dependencies, forceNpm = false) {
dependencies = [].concat(dependencies).join(' ');
if (!forceNpm) {
try {
childProcess.execSync('command -v yarn >/dev/null');
return `yarn add ${dependencies} --dev --production=false`;
} catch (e) {}
}
return `npm install ${dependencies} --save-dev --production=false`;
}
/**
* Complete the install process.
*
* @param {Boolean} abortOnComplete
*/
respond(abortOnComplete) {
if (abortOnComplete) {
console.log(
Log.feedback(
typeof abortOnComplete === 'string'
? abortOnComplete
: 'Finished. Please run Mix again.'
);
process.exit();
if (!argv['$0'].includes('ava')) {
process.exit();
}
}
}
buildInstallCommand(dependencies) {
dependencies = [].concat(dependencies).join(' ');
if (File.exists('yarn.lock')) {
return `yarn add ${dependencies} --dev`;
}
return `npm install ${dependencies} --save-dev`;
}
}
module.exports = Dependencies;

12
node_modules/laravel-mix/src/File.js generated vendored
View File

@@ -1,8 +1,8 @@
let os = require("os");
let os = require('os');
let md5 = require('md5');
let path = require('path');
let fs = require('fs-extra');
let uglify = require('uglify-js');
let Terser = require('terser');
let UglifyCss = require('clean-css');
class File {
@@ -151,7 +151,7 @@ class File {
if (typeof body === 'object') {
body = JSON.stringify(body, null, 4);
}
body = body + os.EOL;
fs.writeFileSync(this.absolutePath, body);
@@ -163,9 +163,7 @@ class File {
* Read the file's contents.
*/
read() {
return fs.readFileSync(this.path(), {
encoding: 'utf-8'
});
return fs.readFileSync(this.path(), 'utf8');
}
/**
@@ -201,7 +199,7 @@ class File {
minify() {
if (this.extension() === '.js') {
this.write(
uglify.minify(this.path(), Config.uglify.uglifyOptions).code
Terser.minify(this.read(), Config.terser.terserOptions).code
);
}

View File

@@ -1,6 +1,7 @@
let concatenate = require('concatenate');
let babel = require('babel-core');
let babel = require('@babel/core');
let glob = require('glob');
let Log = require('./Log');
class FileCollection {
/**
@@ -86,7 +87,7 @@ class FileCollection {
let files = glob.sync(src.path(), { nodir: true });
if (!files.length) {
console.log(
Log.feedback(
`Notice: The ${src.path()} search produced no matches.`
);
}

View File

@@ -64,13 +64,7 @@ class Manifest {
* @param {object} stats
*/
transform(stats) {
let customAssets = Config.customAssets.map(asset =>
asset.pathFromPublic()
);
this.flattenAssets(stats)
.concat(customAssets)
.forEach(this.add.bind(this));
this.flattenAssets(stats).forEach(this.add.bind(this));
return this;
}

24
node_modules/laravel-mix/src/Mix.js generated vendored
View File

@@ -62,6 +62,21 @@ class Mix {
return false;
}
/**
* Determine if the given npm package is installed.
*
* @param {string} npmPackage
*/
seesNpmPackage(npmPackage) {
try {
require.resolve(npmPackage);
return true;
} catch (e) {
return false;
}
}
/**
* Determine if Mix should activate hot reloading.
*/
@@ -71,15 +86,6 @@ class Mix {
return this.isUsing('hmr');
}
/**
* Add a custom file to the webpack assets collection.
*
* @param {string} asset
*/
addAsset(asset) {
Config.customAssets.push(asset);
}
/**
* Queue up a new task.
*

View File

@@ -8,7 +8,7 @@ class Paths {
if (argv['$0'].includes('ava')) {
this.rootPath = path.resolve(__dirname, '../');
} else {
this.rootPath = path.resolve(__dirname, '../../../');
this.rootPath = process.cwd();
}
}

View File

@@ -1,153 +0,0 @@
let File = require('./File');
let path = require('path');
let spawn = require('child_process').spawn;
let notifier = require('node-notifier');
class StandaloneSass {
/**
* Create a new StandaloneSass instance.
*
* @param {string} src
* @param {string} output
* @param {object} pluginOptions
*/
constructor(src, output, pluginOptions) {
this.src = src;
this.output = output;
this.pluginOptions = pluginOptions;
this.shouldWatch = process.argv.includes('--watch');
Mix.addAsset(this.output);
}
/**
* Run the node-sass compiler.
*/
run() {
this.compile();
if (this.shouldWatch) this.watch();
}
/**
* Compile Sass.
*
* @param {Boolean} watch
*/
compile(watch = false) {
this.command = spawn(
path.resolve('./node_modules/.bin/node-sass'),
[this.src.path(), this.output.path()].concat(this.options(watch)),
{ shell: true }
);
this.whenOutputIsAvailable((output, event) => {
if (event === 'error') this.onFail(output);
if (event === 'success') this.onSuccess(output);
});
return this;
}
/**
* Fetch the node-sass options.
*
* @param {Boolean} watch
*/
options(watch) {
let sassOptions = [
'--precision=8',
'--output-style=' + (Mix.inProduction() ? 'compressed' : 'expanded')
];
if (watch) sassOptions.push('--watch');
if (this.pluginOptions.includePaths) {
this.pluginOptions.includePaths.forEach(path =>
sassOptions.push('--include-path=' + path)
);
}
if (this.pluginOptions.importer) {
sassOptions.push('--importer ' + this.pluginOptions.importer);
}
if (Mix.isUsing('sourcemaps') && !Mix.inProduction()) {
sassOptions.push('--source-map-embed');
}
return sassOptions;
}
/**
* Compile Sass, while registering a watcher.
*/
watch() {
return this.compile(true);
}
/**
* Register a callback for when output is available.
*
* @param {Function} callback
*/
whenOutputIsAvailable(callback) {
this.command.stderr.on('data', output => {
output = output.toString();
let event = 'change';
if (output.includes('Error')) event = 'error';
if (output.includes('Wrote CSS')) event = 'success';
callback(output, event);
});
}
/**
* Handle successful compilation.
*
* @param {string} output
*/
onSuccess(output) {
console.log('\n');
console.log(output);
if (Config.notifications.onSuccess) {
notifier.notify({
title: 'Laravel Mix',
message: 'Sass Compilation Successful',
contentImage: 'node_modules/laravel-mix/icons/laravel.png'
});
}
}
/**
* Handle failed compilation.
*
* @param {string} output
*/
onFail(output) {
output = output.replace(
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
''
);
console.log('\n');
console.log('Sass Compilation Failed!');
console.log();
console.log(output);
if (Mix.isUsing('notifications')) {
notifier.notify({
title: 'Laravel Mix',
subtitle: 'Sass Compilation Failed',
message: JSON.parse(output).message,
contentImage: 'node_modules/laravel-mix/icons/laravel.png'
});
}
if (!this.shouldWatch) process.exit();
}
}
module.exports = StandaloneSass;

View File

@@ -58,8 +58,17 @@ class Entry {
);
}
let vendorPath = extraction.output
? new File(extraction.output)
let outputPath = extraction.output;
// If the extraction output path begins with a slash (forward or backward)
// then the path from the public directory determined below will be wrong
// on Windows, as a drive letter will be incorrectly prepended to
// (e.g. '/dist/vendor' -> 'C:\dist\vendor').
let startsWithSlash = ['\\', '/'].indexOf(outputPath[0]) >= 0;
outputPath = startsWithSlash ? outputPath.substr(1) : outputPath;
let vendorPath = outputPath
? new File(outputPath)
.pathFromPublic(Config.publicPath)
.replace(/\.js$/, '')
.replace(/\\/g, '/')
@@ -104,7 +113,11 @@ class Entry {
*/
normalizePath(output, fallback) {
// All output paths need to start at the project's public dir.
if (!output.pathFromPublic().startsWith('/' + Config.publicPath)) {
let pathFromPublicDir = output.pathFromPublic();
if (
!pathFromPublicDir.startsWith('/' + Config.publicPath) &&
!pathFromPublicDir.startsWith('\\' + Config.publicPath)
) {
output = new File(
path.join(Config.publicPath, output.pathFromPublic())
);

View File

@@ -1,9 +1,8 @@
let webpack = require('webpack');
let webpackDefaultConfig = require('./webpack-default');
let Entry = require('./Entry');
let webpackRules = require('./webpack-rules');
let webpackPlugins = require('./webpack-plugins');
let webpackDefaultConfig = require('./webpack-default');
process.noDeprecation = true;
@@ -37,7 +36,7 @@ class WebpackConfig {
buildEntry() {
let entry = new Entry();
if (! Mix.bundlingJavaScript) {
if (!Mix.bundlingJavaScript) {
entry.addDefault();
}
@@ -64,12 +63,9 @@ class WebpackConfig {
filename: '[name].js',
chunkFilename: '[name].js',
publicPath: Mix.isUsing('hmr')
? http +
'://' +
Config.hmrOptions.host +
':' +
Config.hmrOptions.port +
'/'
? `${http}://${Config.hmrOptions.host}:${
Config.hmrOptions.port
}/`
: '/'
};
@@ -107,7 +103,7 @@ class WebpackConfig {
*/
buildResolving() {
this.webpackConfig.resolve = {
extensions: ['*', '.js', '.jsx', '.vue'],
extensions: ['*', '.wasm', '.mjs', '.js', '.jsx', '.json', '.vue'],
alias: {
vue$: 'vue/dist/vue.common.js'

View File

@@ -1,7 +1,12 @@
let TerserPlugin = require('terser-webpack-plugin');
let OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = function() {
return {
context: Mix.paths.root(),
mode: Mix.inProduction() ? 'production' : 'development',
entry: {},
output: {},
@@ -16,17 +21,33 @@ module.exports = function() {
timings: false,
children: false,
errorDetails: false,
entrypoints: false,
performance: Mix.inProduction(),
chunks: false,
modules: false,
reasons: false,
source: false,
publicPath: false
publicPath: false,
builtAt: false
},
performance: {
hints: false
},
optimization: Mix.inProduction()
? {
minimizer: [
new TerserPlugin(Config.terser),
new OptimizeCSSAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', Config.cssNano]
}
})
]
}
: {},
devtool: Config.sourcemaps,
devServer: {

View File

@@ -5,7 +5,6 @@ let BuildCallbackPlugin = require('../webpackPlugins/BuildCallbackPlugin');
let CustomTasksPlugin = require('../webpackPlugins/CustomTasksPlugin');
let ManifestPlugin = require('../webpackPlugins/ManifestPlugin');
let MockEntryPlugin = require('../webpackPlugins/MockEntryPlugin');
let UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = function() {
let plugins = [];
@@ -19,14 +18,11 @@ module.exports = function() {
// Activate better error feedback in the console.
plugins.push(
new FriendlyErrorsWebpackPlugin({ clearConsole: Config.clearConsole })
new FriendlyErrorsWebpackPlugin({
clearConsole: Config.clearConsole
})
);
// Add support for webpack 3 scope hoisting.
if (Mix.inProduction()) {
plugins.push(new webpack.optimize.ModuleConcatenationPlugin());
}
// Activate support for Mix_ .env definitions.
plugins.push(
MixDefinitionsPlugin.build({
@@ -36,27 +32,19 @@ module.exports = function() {
})
);
if (!Mix.components.get('version') && Mix.isUsing('hmr')) {
plugins.push(new webpack.NamedModulesPlugin());
}
// Add some general Webpack loader options.
plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: Mix.inProduction(),
minimize: Mix.isUsing('purifyCss') ? false : Mix.inProduction(),
options: {
context: __dirname,
output: { path: './' }
output: {
path: './'
}
}
})
);
// If we're in production environment, with Uglification turned on, we'll
// clean up and minify all of the user's JS and CSS automatically.
if (Mix.inProduction() && Config.uglify) {
plugins.push(new UglifyJSPlugin(Config.uglify));
}
// Handle all custom, non-webpack tasks.
plugins.push(new ManifestPlugin());

View File

@@ -10,7 +10,7 @@ module.exports = function() {
// Add support for loading images.
rules.push({
// only include svg that doesn't have font in the path or file name by using negative lookahead
test: /(\.(png|jpe?g|gif)$|^((?!font).)*\.svg$)/,
test: /(\.(png|jpe?g|gif|webp)$|^((?!font).)*\.svg$)/,
loaders: [
{
loader: 'file-loader',

View File

@@ -10,7 +10,9 @@ class Autoload {
Object.keys(libs).forEach(library => {
[].concat(libs[library]).forEach(alias => {
aliases[alias] = library.includes('.') ? library.split('.') : library;
aliases[alias] = library.includes('.')
? library.split('.')
: library;
});
});

View File

@@ -5,7 +5,7 @@ class Coffee extends JavaScript {
* Required dependencies for the component.
*/
dependencies() {
return ['coffee-loader', 'coffeescript'].concat(super.dependencies());
return ['coffee-loader', 'coffeescript'].concat();
}
/**

View File

@@ -8,7 +8,6 @@ let components = [
'React',
'Coffee',
'TypeScript',
'FastSass',
'Less',
'Sass',
'Stylus',
@@ -23,7 +22,8 @@ let components = [
'Extract',
'Notifications',
'DisableNotifications',
'PurifyCss'
'PurifyCss',
'DumpWebpackConfig'
];
class ComponentFactory {

View File

@@ -8,19 +8,83 @@ class Css extends AutomaticComponent {
return [
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
loaders: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
{
loader: 'postcss-loader',
options: this.postCssOptions()
}
]
},
{
test: /\.s[ac]ss$/,
test: /\.scss$/,
exclude: this.excludePathsFor('sass'),
loaders: ['style-loader', 'css-loader', 'sass-loader']
loaders: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: this.postCssOptions()
},
{
loader: 'sass-loader',
options: {
precision: 8,
outputStyle: 'expanded'
}
}
]
},
{
test: /\.sass$/,
exclude: this.excludePathsFor('sass'),
loaders: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: this.postCssOptions()
},
{
loader: 'sass-loader',
options: {
precision: 8,
outputStyle: 'expanded',
indentedSyntax: true
}
}
]
},
{
test: /\.less$/,
exclude: this.excludePathsFor('less'),
loaders: ['style-loader', 'css-loader', 'less-loader']
loaders: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: this.postCssOptions()
},
'less-loader'
]
},
{
test: /\.styl(us)?$/,
exclude: this.excludePathsFor('stylus'),
loaders: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: this.postCssOptions()
},
'stylus-loader'
]
}
];
}
@@ -37,6 +101,25 @@ class Css extends AutomaticComponent {
? exclusions.details.map(preprocessor => preprocessor.src.path())
: [];
}
/**
* Fetch the appropriate postcss plugins for the compile.
*/
postCssOptions() {
if (Mix.components.get('postCss')) {
return {
plugins: Mix.components.get('postCss').details[0].postCssPlugins
};
}
// If the user has a postcss.config.js file in their project root,
// postcss-loader will automatically read and fetch the plugins.
if (File.exists(Mix.paths.root('postcss.config.js'))) {
return {};
}
return { plugins: Config.postCss };
}
}
module.exports = Css;

View File

@@ -114,7 +114,7 @@ class Example {
*/
babelConfig() {
// Example:
// return { presets: ['react'] };
// return { presets: ['@babel/preset-react'] };
}
}

View File

@@ -1,20 +1,41 @@
let webpack = require('webpack');
let webpackMerge = require('webpack-merge');
class Extract {
/**
* Create a new component instance.
*/
constructor() {
this.entry = null;
this.extractions = [];
}
/**
* The name of the component.
*
* mix.extract() or mix.extractVendor()
*/
name() {
return ['extract', 'extractVendors'];
}
/**
* Register the component.
*
* @param {*} libs
* @param {string} output
*/
register(libs, output) {
register(libs = [], output) {
// If the user provides an output path as the first argument, they probably
// want to extract all node_module libraries to the specified file.
if (
arguments.length === 1 &&
typeof libs === 'string' &&
libs.endsWith('.js')
) {
output = libs;
libs = [];
}
this.extractions.push({ libs, output });
}
@@ -24,32 +45,81 @@ class Extract {
* @param {Entry} entry
*/
webpackEntry(entry) {
this.extractions = this.extractions.map(
entry.addExtraction.bind(entry)
);
this.entry = entry;
// If we are extracting vendor libraries, then we also need
// to extract Webpack's manifest file to assist with caching.
if (this.extractions.length) {
this.extractions.push(
path.join(entry.base, 'manifest').replace(/\\/g, '/')
);
}
this.extractions.forEach(extraction => {
extraction.output = this.extractionPath(extraction.output);
if (extraction.libs.length) {
this.entry.addExtraction(extraction);
}
});
}
/**
* webpack plugins to be appended to the master config.
*/
webpackPlugins() {
// If we're extracting any vendor libraries, then we
// need to add the CommonChunksPlugin to strip out
// all relevant code into its own file.
if (this.extractions.length) {
return new webpack.optimize.CommonsChunkPlugin({
names: this.extractions,
minChunks: Infinity
});
webpackConfig(config) {
const newConfig = webpackMerge.smart(config, this.config());
config.optimization = newConfig.optimization;
}
config() {
return {
optimization: {
// If we are extracting vendor libraries, then we also need
// to extract Webpack's manifest file to assist with caching.
runtimeChunk: {
name: path
.join(this.entry.base, 'manifest')
.replace(/\\/g, '/')
},
splitChunks: this.createSplitChunks()
}
};
}
createSplitChunks() {
let config = { cacheGroups: {} };
for (const [index, extraction] of this.extractions.entries()) {
if (extraction.libs.length) {
config.cacheGroups[`vendor${index}`] = this.createCacheGroup(
extraction
);
}
}
// If the user didn't specify any libraries to extract,
// they likely want to extract all vendor libraries.
if (Object.keys(config.cacheGroups).length === 0) {
config.chunks = 'all';
config.name = this.extractions[0].output;
}
return config;
}
createCacheGroup(extraction) {
const libsPattern = extraction.libs.join('|');
const pattern = new RegExp(`node_modules[\\\\/](${libsPattern})`, 'i');
return {
test: pattern,
name: extraction.output,
chunks: 'all',
enforce: true
};
}
extractionPath(outputPath) {
if (outputPath) {
return new File(outputPath)
.pathFromPublic(Config.publicPath)
.replace(/\.js$/, '')
.replace(/\\/g, '/');
}
return path.join(this.entry.base, 'vendor').replace(/\\/g, '/');
}
}

View File

@@ -1,37 +0,0 @@
let Preprocessor = require('./Preprocessor');
let Assert = require('../Assert');
class FastSass extends Preprocessor {
/**
* The API name for the component.
*/
name() {
return ['fastSass', 'standaloneSass'];
}
/**
* Register the component.
*
* @param {*} src
* @param {string} output
* @param {Object} pluginOptions
*/
register(src, output, pluginOptions = {}) {
Assert.exists(src);
return this.preprocess('fastSass', src, output, pluginOptions);
}
/**
* webpack plugins to be appended to the master config.
*/
webpackPlugins() {
let FastSassPlugin = require('../webpackPlugins/FastSassPlugin');
return (super.webpackPlugins() || []).concat(
new FastSassPlugin(this.details)
);
}
}
module.exports = FastSass;

View File

@@ -1,12 +1,13 @@
let glob = require('glob');
let Assert = require('../Assert');
let MockEntryPlugin = require('../webpackPlugins/MockEntryPlugin');
let Vue = require('./Vue');
class JavaScript {
constructor() {
this.vue = new Vue();
this.toCompile = [];
JavaScript.vueWebpackConfigApplied = false;
}
/**
@@ -65,7 +66,7 @@ class JavaScript {
* webpack rules to be appended to the master config.
*/
webpackRules() {
return [
return [].concat([
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
@@ -76,7 +77,7 @@ class JavaScript {
}
]
}
];
]);
}
/**
@@ -85,7 +86,11 @@ class JavaScript {
* @param {Object} webpackConfig
*/
webpackConfig(webpackConfig) {
this.vue.webpackConfig(webpackConfig);
if (!JavaScript.vueWebpackConfigApplied) {
this.vue.webpackConfig(webpackConfig);
}
JavaScript.vueWebpackConfigApplied = true;
}
}

View File

@@ -14,9 +14,16 @@ class Less extends Preprocessor {
* @param {*} src
* @param {string} output
* @param {Object} pluginOptions
* @param {Array} postCssPlugins
*/
register(src, output, pluginOptions = {}) {
this.preprocess('less', src, output, pluginOptions);
register(src, output, pluginOptions = {}, postCssPlugins = []) {
return this.preprocess(
'less',
src,
output,
pluginOptions,
postCssPlugins
);
}
}

View File

@@ -11,7 +11,11 @@ class Notifications extends AutomaticComponent {
return new WebpackNotifierPlugin({
title: 'Laravel Mix',
alwaysNotify: Config.notifications.onSuccess,
hint: process.platform === 'linux' ? 'int:transient:1' : undefined,
hint:
process.platform === 'linux'
? 'int:transient:1'
: undefined,
timeout: 2,
contentImage: Mix.paths.root(
'node_modules/laravel-mix/icons/laravel.png'
)

View File

@@ -9,8 +9,6 @@ class Preprocessor {
*/
webpackEntry(entry) {
this.details.forEach(detail => {
if (detail.type === 'fastsass') return;
entry.add(entry.keys()[0], detail.src.path());
});
}
@@ -22,8 +20,6 @@ class Preprocessor {
let rules = [];
this.details.forEach(preprocessor => {
if (preprocessor.type === 'fastsass') return;
let outputPath = preprocessor.output.filePath
.replace(Config.publicPath + path.sep, path.sep)
.replace(/\\/g, '/');
@@ -88,22 +84,18 @@ class Preprocessor {
if (preprocessor.type !== 'postCss') {
loaders.push({
loader: `${preprocessor.type}-loader`,
options: Object.assign(preprocessor.pluginOptions, {
sourceMap:
preprocessor.type === 'sass' &&
Config.processCssUrls
? true
: Mix.isUsing('sourcemaps')
})
options: this.loaderOptions(preprocessor)
});
}
rules.push({
test: preprocessor.src.path(),
use: extractPlugin.extract({
fallback: 'style-loader',
use: loaders
})
use: Mix.isUsing('hmr')
? ['style-loader', ...loaders]
: extractPlugin.extract({
fallback: 'style-loader',
use: loaders
})
});
this.extractPlugins = (this.extractPlugins || []).concat(
@@ -122,6 +114,26 @@ class Preprocessor {
return this.extractPlugins;
}
/**
* Prepare the preprocessor plugin options.
*
* @param {Object} preprocessor
*/
loaderOptions(preprocessor) {
tap(preprocessor.pluginOptions.implementation, implementation => {
if (typeof implementation === 'function') {
preprocessor.pluginOptions.implementation = implementation();
}
});
return Object.assign(preprocessor.pluginOptions, {
sourceMap:
preprocessor.type === 'sass' && Config.processCssUrls
? true
: Mix.isUsing('sourcemaps')
});
}
/**
* Register a generic CSS preprocessor.
*
@@ -129,8 +141,9 @@ class Preprocessor {
* @param {string} src
* @param {string} output
* @param {object} pluginOptions
* @param {Array} postCssPlugins
*/
preprocess(type, src, output, pluginOptions = {}) {
preprocess(type, src, output, pluginOptions = {}, postCssPlugins = []) {
Assert.preprocessor(type, src, output);
src = new File(src);
@@ -144,13 +157,10 @@ class Preprocessor {
type: this.constructor.name.toLowerCase(),
src,
output,
pluginOptions
pluginOptions,
postCssPlugins
});
if (type === 'fastSass') {
Mix.addAsset(output);
}
return this;
}

View File

@@ -34,16 +34,21 @@ class PurifyCss extends AutomaticComponent {
* @param {Object} options
*/
build(options) {
if (typeof options === 'object' && options.paths) {
let paths = options.paths;
if (typeof options === 'object') {
if (options.paths) {
let paths = options.paths;
paths.forEach(path => {
if (!path.includes('*')) return;
paths.forEach(path => {
if (!path.includes('*')) return;
options.paths.splice(paths.indexOf(path), 1);
options.paths.splice(paths.indexOf(path), 1);
options.paths = paths.concat(glob.sync(path));
});
options.paths = paths.concat(glob.sync(path));
});
}
options.minimize = options.hasOwnProperty('minimize')
? options.minimize
: Mix.inProduction();
}
return options;

View File

@@ -5,7 +5,7 @@ class React extends JavaScript {
* Required dependencies for the component.
*/
dependencies() {
return ['babel-preset-react'].concat(super.dependencies());
return ['@babel/preset-react'];
}
/**
@@ -13,7 +13,7 @@ class React extends JavaScript {
*/
babelConfig() {
return {
presets: ['react']
presets: ['@babel/preset-react']
};
}
}

View File

@@ -1,19 +1,40 @@
let Preprocessor = require('./Preprocessor');
class Sass extends Preprocessor {
/**
* Required dependencies for the component.
*/
dependencies() {
this.requiresReload = true;
return tap(
[
'sass-loader@7.*',
Mix.seesNpmPackage('node-sass') ? 'node-sass' : 'sass'
],
dependencies => {
if (Config.processCssUrls) {
dependencies.push('resolve-url-loader@2.3.1');
}
}
);
}
/**
* Register the component.
*
* @param {*} src
* @param {string} output
* @param {Object} pluginOptions
* @param {Array} postCssPlugins
*/
register(src, output, pluginOptions = {}) {
register(src, output, pluginOptions = {}, postCssPlugins = []) {
return this.preprocess(
'sass',
src,
output,
this.pluginOptions(pluginOptions)
this.pluginOptions(pluginOptions),
postCssPlugins
);
}
@@ -27,7 +48,8 @@ class Sass extends Preprocessor {
return Object.assign(
{
precision: 8,
outputStyle: 'expanded'
outputStyle: 'expanded',
implementation: () => require('sass')
},
pluginOptions,
{ sourceMap: true }

View File

@@ -14,8 +14,9 @@ class Stylus extends Preprocessor {
* @param {*} src
* @param {string} output
* @param {Object} pluginOptions
* @param {Array} postCssPlugins
*/
register(src, output, pluginOptions = {}) {
register(src, output, pluginOptions = {}, postCssPlugins = []) {
pluginOptions = Object.assign(
{
preferPathResolver: 'webpack'
@@ -23,7 +24,13 @@ class Stylus extends Preprocessor {
pluginOptions
);
return this.preprocess('stylus', src, output, pluginOptions);
return this.preprocess(
'stylus',
src,
output,
pluginOptions,
postCssPlugins
);
}
}

View File

@@ -12,7 +12,7 @@ class TypeScript extends JavaScript {
* Required dependencies for the component.
*/
dependencies() {
return ['ts-loader', 'typescript'].concat(super.dependencies());
return ['ts-loader', 'typescript'].concat();
}
/**
@@ -35,7 +35,7 @@ class TypeScript extends JavaScript {
* @param {Object} config
*/
webpackConfig(config) {
super.webpackConfig(config)
super.webpackConfig(config);
config.resolve.extensions.push('.ts', '.tsx');
config.resolve.alias['vue$'] = 'vue/dist/vue.esm.js';

View File

@@ -32,16 +32,9 @@ class Version {
* webpack plugins to be appended to the master config.
*/
webpackPlugins() {
let WebpackChunkHashPlugin = require('webpack-chunk-hash');
return [
new webpack[
Mix.inProduction()
? 'HashedModuleIdsPlugin'
: 'NamedModulesPlugin'
](),
new WebpackChunkHashPlugin()
];
if (Mix.inProduction()) {
return [new webpack.HashedModuleIdsPlugin()];
}
}
}

View File

@@ -1,20 +1,19 @@
let { VueLoaderPlugin } = require('vue-loader');
let ExtractTextPlugin = require('extract-text-webpack-plugin');
let { without } = require('lodash');
class Vue {
/**
* Create a new Vue instance.
*/
constructor() {
this.requiresNewCssExtract = false;
}
/**
* Required dependencies for the component.
*/
dependencies() {
let dependencies = ['vue-template-compiler'];
if (Config.extractVueStyles && Config.globalVueStyles) {
return ['sass-resources-loader']; // Required for importing global styles into every component.
dependencies.push('sass-resources-loader');
}
return dependencies;
}
/**
@@ -22,127 +21,157 @@ class Vue {
*
* @param {Object} webpackConfig
*/
webpackConfig(config) {
let { vueLoaderOptions, extractPlugin } = this.vueLoaderOptions();
config.module.rules.push({
webpackConfig(webpackConfig) {
webpackConfig.module.rules.push({
test: /\.vue$/,
loader: 'vue-loader',
exclude: /bower_components/,
options: vueLoaderOptions
loader: 'vue-loader'
});
if (this.requiresNewCssExtract) {
config.plugins.push(extractPlugin);
}
webpackConfig.plugins.push(new VueLoaderPlugin());
this.updateCssLoaders(webpackConfig);
}
/**
* vue-loader-specific options.
* Update all preprocessor loaders to support CSS extraction.
*
* @param {Object} webpackConfig
*/
vueLoaderOptions() {
let extractPlugin = this.extractPlugin();
updateCssLoaders(webpackConfig) {
// Basic CSS and PostCSS
this.updateCssLoader('css', webpackConfig, rule => {
rule.loaders.find(
loader => loader.loader === 'postcss-loader'
).options = this.postCssOptions();
});
if (Config.extractVueStyles) {
var sassLoader = extractPlugin.extract({
use: 'css-loader!sass-loader?indentedSyntax',
fallback: 'vue-style-loader'
});
// LESS
this.updateCssLoader('less', webpackConfig);
var scssLoader = extractPlugin.extract({
use: 'css-loader!sass-loader',
fallback: 'vue-style-loader'
});
// SASS
let sassCallback = rule => {
if (Mix.seesNpmPackage('sass')) {
rule.loaders.find(
loader => loader.loader === 'sass-loader'
).options.implementation = require('sass');
}
if (Config.globalVueStyles) {
scssLoader.push({
loader: 'sass-resources-loader',
options: {
resources: Mix.paths.root(Config.globalVueStyles)
}
});
sassLoader.push({
rule.loaders.push({
loader: 'sass-resources-loader',
options: {
resources: Mix.paths.root(Config.globalVueStyles)
}
});
}
}
};
let vueLoaderOptions = Object.assign(
{
loaders: Config.extractVueStyles
? {
js: {
loader: 'babel-loader',
options: Config.babel()
},
// SCSS
this.updateCssLoader('scss', webpackConfig, sassCallback);
scss: scssLoader,
// SASS
this.updateCssLoader('sass', webpackConfig, sassCallback);
sass: sassLoader,
css: extractPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader'
}),
stylus: extractPlugin.extract({
use:
'css-loader!stylus-loader?paths[]=node_modules',
fallback: 'vue-style-loader'
}),
less: extractPlugin.extract({
use: 'css-loader!less-loader',
fallback: 'vue-style-loader'
})
}
: {
js: {
loader: 'babel-loader',
options: Config.babel()
}
},
postcss: Config.postCss
},
Config.vue
);
return { vueLoaderOptions, extractPlugin };
// STYLUS
this.updateCssLoader('styl', webpackConfig);
}
extractPlugin() {
if (typeof Config.extractVueStyles === 'string') {
this.requiresNewCssExtract = true;
/**
* Update a single CSS loader.
*
* @param {string} loader
* @param {Object} webpackConfig
* @param {Function} callback
*/
updateCssLoader(loader, webpackConfig, callback) {
let rule = webpackConfig.module.rules.find(rule => {
return rule.test instanceof RegExp && rule.test.test('.' + loader);
});
return new ExtractTextPlugin(this.extractFilePath());
}
callback && callback(rule);
let preprocessorName = Object.keys(Mix.components.all())
.reverse()
.find(componentName => {
return ['sass', 'less', 'stylus', 'postCss'].includes(
componentName
);
if (Config.extractVueStyles) {
let extractPlugin = this.extractPlugin();
rule.loaders = extractPlugin.extract({
fallback: 'style-loader',
use: without(rule.loaders, 'style-loader')
});
if (!preprocessorName) {
this.requiresNewCssExtract = true;
return new ExtractTextPlugin(this.extractFilePath());
this.addExtractPluginToConfig(extractPlugin, webpackConfig);
}
return Mix.components.get(preprocessorName).extractPlugins.slice(-1)[0];
}
extractFilePath() {
/**
* Fetch the appropriate postcss plugins for the compile.
*/
postCssOptions() {
if (Mix.components.get('postCss')) {
return {
plugins: Mix.components.get('postCss').details[0].postCssPlugins
};
}
// If the user has a postcss.config.js file in their project root,
// postcss-loader will automatically read and fetch the plugins.
if (File.exists(Mix.paths.root('postcss.config.js'))) {
return {};
}
return { plugins: Config.postCss };
}
/**
* Add an extract text plugin to the webpack config plugins array.
*
* @param {Object} extractPlugin
* @param {Object} webpackConfig
*/
addExtractPluginToConfig(extractPlugin, webpackConfig) {
if (extractPlugin.isNew) {
webpackConfig.plugins.push(extractPlugin);
}
}
/**
* Fetch the appropriate extract plugin.
*/
extractPlugin() {
// If the user set extractVueStyles: true, we'll try
// to append the Vue styles to an existing CSS chunk.
if (typeof Config.extractVueStyles === 'boolean') {
let preprocessorName = Object.keys(Mix.components.all())
.reverse()
.find(componentName => {
return ['sass', 'less', 'stylus', 'postCss'].includes(
componentName
);
});
if (preprocessorName) {
return Mix.components
.get(preprocessorName)
.extractPlugins.slice(-1)[0];
}
}
// Otherwise, we'll need to whip up a fresh extract text instance.
return tap(
new ExtractTextPlugin(this.extractFileName()),
extractPlugin => {
extractPlugin.isNew = true;
}
);
}
/**
* Determine the extract file name.
*/
extractFileName() {
let fileName =
typeof Config.extractVueStyles === 'string'
? Config.extractVueStyles
: 'vue-styles.css';
: '/css/vue-styles.css';
return fileName.replace(Config.publicPath, '').replace(/^\//, '');
}

View File

@@ -1,6 +1,3 @@
let paths = new (require('./Paths'))();
let webpackMerge = require('webpack-merge');
module.exports = function() {
return {
/**
@@ -12,13 +9,6 @@ module.exports = function() {
process.env.NODE_ENV === 'production' ||
process.argv.includes('-p'),
/**
* A list of custom assets that are being compiled outside of Webpack.
*
* @type {Array}
*/
customAssets: [],
/**
* Determine if we should enable hot reloading.
*
@@ -96,17 +86,6 @@ module.exports = function() {
*/
resourceRoot: '/',
/**
* vue-loader specific options.
*
* @type {Object}
*/
vue: {
preLoaders: {},
postLoaders: {},
esModule: false
},
/**
* Image Loader defaults.
* See: https://github.com/thetalecrafter/img-loader#options
@@ -134,68 +113,38 @@ module.exports = function() {
/**
* The default Babel configuration.
*
* @type {Object}
* @type {String} babelRcPath
*/
babel: function() {
let options = {};
babel: function(babelRcPath) {
babelRcPath = babelRcPath || Mix.paths.root('.babelrc');
tap(Mix.paths.root('.babelrc'), babelrc => {
if (File.exists(babelrc)) {
options = JSON.parse(File.find(babelrc).read());
}
});
if (this.babelConfig) {
options = webpackMerge.smart(options, this.babelConfig);
}
return webpackMerge.smart(
{
cacheDirectory: true,
presets: [
[
'env',
{
modules: false,
targets: {
browsers: ['> 2%'],
uglify: true
}
}
]
],
plugins: [
'transform-object-rest-spread',
[
'transform-runtime',
{
polyfill: false,
helpers: false
}
]
]
},
options
return require('./BabelConfig').generate(
this.babelConfig,
babelRcPath
);
},
/**
* Determine if CSS url()s should be processed by Webpack.
* Determine if CSS relative url()s should be calculated by Sass Webpack,
* using resolve-url-loader. Disabling this can improve performance
* greatly.
*
* @type {Boolean}
*/
processCssUrls: true,
/**
* Whether to extract .vue component styles into a dedicated file.
* Should we extract .vue component styles into a dedicated file?
* You may provide a boolean, or a dedicated path to extract to.
*
* Ex: extractVueStyles: '/css/vue.css'
*
* @type {Boolean|string}
*/
extractVueStyles: false,
/**
* File with global styles to be imported in every component.
* A file path with global styles that shuold be imported into every Vue component.
*
* See: https://vue-loader.vuejs.org/en/configurations/pre-processors.html#loading-a-global-settings-file
*
@@ -204,15 +153,17 @@ module.exports = function() {
globalVueStyles: '',
/**
* Uglify-specific settings for Webpack.
* Terser-specific settings for Webpack.
*
* See: https://github.com/mishoo/UglifyJS2#compressor-options
* See: https://github.com/webpack-contrib/terser-webpack-plugin#options
*
* @type {Object}
*/
uglify: {
terser: {
cache: true,
parallel: true,
sourceMap: true,
uglifyOptions: {
terserOptions: {
compress: {
warnings: false
},
@@ -222,6 +173,15 @@ module.exports = function() {
}
},
/**
* cssnano-specific settings for Webpack.
*
* See: https://cssnano.co/optimisations/
*
* @type {Object}
*/
cssNano: {},
/**
* CleanCss-specific settings for Webpack.
*

View File

@@ -45,14 +45,12 @@ if (Mix.sees('laravel')) {
Mix.listen('init', () => {
if (Mix.shouldHotReload()) {
let http = process.argv.includes('--https') ? 'https' : 'http';
let port = process.argv.includes('--port')
? process.argv[process.argv.indexOf('--port') + 1]
: Config.hmrOptions.port;
new File(path.join(Config.publicPath, 'hot')).write(
http +
'://' +
Config.hmrOptions.host +
':' +
Config.hmrOptions.port +
'/'
http + '://' + Config.hmrOptions.host + ':' + port + '/'
);
}
});
@@ -67,5 +65,4 @@ let Api = require('./Api');
let api = new Api();
module.exports = api;
module.exports.mix = api; // Deprecated.
module.exports.config = Config;

View File

@@ -1,5 +1,6 @@
let Task = require('./Task');
let FileCollection = require('../FileCollection');
let Log = require('../Log');
const path = require('path');
class CopyFilesTask extends Task {
@@ -37,7 +38,7 @@ class CopyFilesTask extends Task {
);
}
console.log(`Copying ${updatedFile} to ${destination.path()}`);
Log.feedback(`Copying ${updatedFile} to ${destination.path()}`);
this.files.copyTo(destination, new File(updatedFile));
}

View File

@@ -1,3 +1,5 @@
let Log = require('../Log');
class CustomTasksPlugin {
/**
* Apply the plugin.
@@ -48,7 +50,10 @@ class CustomTasksPlugin {
*/
minifyAssets() {
let tasks = Mix.tasks.filter(task => {
return task.constructor.name !== 'VersionFilesTask' && task.constructor.name !== 'CopyFilesTask';
return (
task.constructor.name !== 'VersionFilesTask' &&
task.constructor.name !== 'CopyFilesTask'
);
});
tasks.forEach(task => {
@@ -56,7 +61,7 @@ class CustomTasksPlugin {
try {
asset.minify();
} catch (e) {
console.log(
Log.error(
`Whoops! We had trouble minifying "${asset.relativePath()}". ` +
`Perhaps you need to use mix.babel() instead?`
);

View File

@@ -1,27 +0,0 @@
let StandaloneSass = require('../StandaloneSass');
class FastSassPlugin {
/**
* Create a new plugin instance.
*
* @param {Array} files
*/
constructor(files = []) {
this.files = files;
}
/**
* Apply the plugin.
*/
apply() {
this.files.forEach(sass => {
new StandaloneSass(
sass.src,
sass.output.forceFromPublic(),
sass.pluginOptions
).run();
});
}
}
module.exports = FastSassPlugin;