ui
This commit is contained in:
+113
@@ -0,0 +1,113 @@
|
||||
let path = require('path');
|
||||
let File = require('../File');
|
||||
|
||||
class Entry {
|
||||
/**
|
||||
* Create a new Entry instance.
|
||||
* @param {import("../Mix")} mix
|
||||
*/
|
||||
constructor(mix) {
|
||||
// TODO: Simplify in Mix 7 -- Here for backwards compat if a plugin creates this class directly
|
||||
this.mix = mix || global.Mix;
|
||||
|
||||
/** @type {Record<string, string[]>} */
|
||||
this.structure = {};
|
||||
this.base = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the underlying entry structure.
|
||||
*/
|
||||
get() {
|
||||
return this.structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object keys for the structure.
|
||||
*/
|
||||
keys() {
|
||||
return Object.keys(this.structure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a key key-val pair to the structure.
|
||||
*
|
||||
* @param {string} key
|
||||
* @param {any} val
|
||||
*/
|
||||
add(key, val) {
|
||||
this.structure[key] = (this.structure[key] || []).concat(val);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new key-val pair, based on a given output path.
|
||||
*
|
||||
* @param {any} val
|
||||
* @param {File} output
|
||||
* @param {File} fallback
|
||||
*/
|
||||
addFromOutput(val, output, fallback) {
|
||||
output = this.normalizePath(output, fallback);
|
||||
|
||||
return this.add(this.createName(output), val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a default entry script to the structure.
|
||||
*/
|
||||
addDefault() {
|
||||
this.add('mix', new File(path.resolve(__dirname, 'mock-entry.js')).path());
|
||||
}
|
||||
|
||||
hasDefault() {
|
||||
return (this.structure.mix || []).some(path => path.includes('mock-entry.js'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the proper entry name, based on a given output.
|
||||
*
|
||||
* @param {File} output
|
||||
*/
|
||||
createName(output) {
|
||||
let name = output
|
||||
.pathFromPublic(this.mix.config.publicPath)
|
||||
.replace(/\.js$/, '')
|
||||
.replace(/\\/g, '/');
|
||||
|
||||
this.base = path.parse(name).dir;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize the given output path.
|
||||
*
|
||||
* @param {File} output
|
||||
* @param {File} fallback
|
||||
*/
|
||||
normalizePath(output, fallback) {
|
||||
// All output paths need to start at the project's public dir.
|
||||
let pathFromPublicDir = output.pathFromPublic();
|
||||
if (
|
||||
!pathFromPublicDir.startsWith('/' + this.mix.config.publicPath) &&
|
||||
!pathFromPublicDir.startsWith('\\' + this.mix.config.publicPath)
|
||||
) {
|
||||
output = new File(
|
||||
path.join(this.mix.config.publicPath, output.pathFromPublic())
|
||||
);
|
||||
}
|
||||
|
||||
// If the output points to a directory, we'll grab a file name from the fallback src.
|
||||
if (output.isDirectory()) {
|
||||
output = new File(
|
||||
path.join(output.filePath, fallback.nameWithoutExtension() + '.js')
|
||||
);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Entry;
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
// @ts-nocheck
|
||||
|
||||
// This code was taken from v4.2.2 of webpack-merge for backwards compatability.
|
||||
// With minor modifications since Mix is not transpiled before running in Node.
|
||||
// Sources:
|
||||
// 1. https://github.com/survivejs/webpack-merge/blob/v4.2.2/src/index.js
|
||||
// 2. https://github.com/survivejs/webpack-merge/blob/v4.2.2/src/join-arrays-smart.js
|
||||
|
||||
const { isEqual, mergeWith, differenceWith, unionWith } = require('lodash');
|
||||
|
||||
function isRule(key) {
|
||||
return ['preLoaders', 'loaders', 'postLoaders', 'rules'].indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
const isArray = Array.isArray;
|
||||
|
||||
function uniteRules(rules, key, newRule, rule) {
|
||||
if (
|
||||
String(rule.test) !== String(newRule.test) ||
|
||||
((newRule.enforce || rule.enforce) && rule.enforce !== newRule.enforce) ||
|
||||
(newRule.include && !isSameValue(rule.include, newRule.include)) ||
|
||||
(newRule.exclude && !isSameValue(rule.exclude, newRule.exclude))
|
||||
) {
|
||||
return false;
|
||||
} else if (
|
||||
!rule.test &&
|
||||
!rule.include &&
|
||||
!rule.exclude &&
|
||||
(rule.loader && rule.loader.split('?')[0]) !==
|
||||
(newRule.loader && newRule.loader.split('?')[0])
|
||||
) {
|
||||
// Don't merge the rule if there isn't any identifying fields and the loaders don't match
|
||||
return false;
|
||||
} else if ((rule.include || rule.exclude) && !newRule.include && !newRule.exclude) {
|
||||
// Don't merge child without include/exclude to parent that has either
|
||||
return false;
|
||||
}
|
||||
|
||||
// apply the same logic for oneOf
|
||||
if (rule.oneOf && newRule.oneOf) {
|
||||
rule.oneOf = unionWith(
|
||||
rule.oneOf,
|
||||
newRule.oneOf,
|
||||
uniteRules.bind(null, {}, 'oneOf')
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// newRule.loader should always override use, loaders and oneOf
|
||||
if (newRule.loader) {
|
||||
const optionsKey = newRule.options ? 'options' : newRule.query && 'query';
|
||||
|
||||
delete rule.use;
|
||||
delete rule.loaders;
|
||||
delete rule.oneOf;
|
||||
|
||||
rule.loader = newRule.loader;
|
||||
|
||||
if (optionsKey) {
|
||||
rule[optionsKey] = newRule[optionsKey];
|
||||
}
|
||||
} else if (newRule.oneOf) {
|
||||
delete rule.use;
|
||||
delete rule.loaders;
|
||||
delete rule.loader;
|
||||
|
||||
rule.oneOf = newRule.oneOf;
|
||||
} else if (
|
||||
(rule.use || rule.loaders || rule.loader) &&
|
||||
(newRule.use || newRule.loaders)
|
||||
) {
|
||||
const expandEntry = loader => (typeof loader === 'string' ? { loader } : loader);
|
||||
// this is only here to avoid breaking existing tests
|
||||
const unwrapEntry = entry =>
|
||||
!entry.options && !entry.query ? entry.loader : entry;
|
||||
|
||||
let entries;
|
||||
if (rule.loader) {
|
||||
const optionsKey = rule.options ? 'options' : rule.query && 'query';
|
||||
entries = [{ loader: rule.loader }];
|
||||
|
||||
if (optionsKey) {
|
||||
entries[0][optionsKey] = rule[optionsKey];
|
||||
}
|
||||
|
||||
delete rule.loader;
|
||||
|
||||
if (optionsKey) {
|
||||
delete rule[optionsKey];
|
||||
}
|
||||
} else {
|
||||
entries = [].concat(rule.use || rule.loaders).map(expandEntry);
|
||||
}
|
||||
const newEntries = [].concat(newRule.use || newRule.loaders).map(expandEntry);
|
||||
|
||||
const loadersKey = rule.use || newRule.use ? 'use' : 'loaders';
|
||||
const resolvedKey = `${key}.${loadersKey}`;
|
||||
|
||||
switch (rules[resolvedKey]) {
|
||||
case 'prepend':
|
||||
rule[loadersKey] = [
|
||||
...differenceWith(newEntries, entries, uniteEntries),
|
||||
...entries
|
||||
].map(unwrapEntry);
|
||||
break;
|
||||
case 'replace':
|
||||
rule[loadersKey] = newRule.use || newRule.loaders;
|
||||
break;
|
||||
default:
|
||||
rule[loadersKey] = combineEntries(newEntries, entries).map(unwrapEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if (newRule.include) {
|
||||
rule.include = newRule.include;
|
||||
}
|
||||
|
||||
if (newRule.exclude) {
|
||||
rule.exclude = newRule.exclude;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check equality of two values using lodash's isEqual
|
||||
* Arrays need to be sorted for equality checking
|
||||
* but clone them first so as not to disrupt the sort order in tests
|
||||
*/
|
||||
function isSameValue(a, b) {
|
||||
const [propA, propB] = [a, b].map(value =>
|
||||
isArray(value) ? [...value].sort() : value
|
||||
);
|
||||
|
||||
return isEqual(propA, propB);
|
||||
}
|
||||
|
||||
function areEqualEntries(newEntry, entry) {
|
||||
const loaderNameRe = /^([^?]+)/gi;
|
||||
|
||||
const [loaderName] = entry.loader.match(loaderNameRe);
|
||||
const [newLoaderName] = newEntry.loader.match(loaderNameRe);
|
||||
|
||||
return loaderName === newLoaderName;
|
||||
}
|
||||
|
||||
function uniteEntries(newEntry, entry) {
|
||||
if (areEqualEntries(newEntry, entry)) {
|
||||
// Replace query values with newer ones
|
||||
mergeWith(entry, newEntry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Combines entries and newEntries, while respecting the order of loaders in each.
|
||||
|
||||
Iterates through new entries. If the new entry also exists in existing entries,
|
||||
we'll put in all of the loaders from existing entries that come before it (in case
|
||||
those are pre-requisites). Any remaining existing entries are added at the end.
|
||||
|
||||
Since webpack processes right-to-left, we're working backwards through the arrays
|
||||
*/
|
||||
function combineEntries(newEntries, existingEntries) {
|
||||
const resultSet = [];
|
||||
|
||||
// We're iterating through newEntries, this keeps track of where we are in the existingEntries
|
||||
let existingEntriesIteratorIndex = existingEntries.length - 1;
|
||||
|
||||
for (let i = newEntries.length - 1; i >= 0; i -= 1) {
|
||||
const currentEntry = newEntries[i];
|
||||
const indexInExistingEntries = findLastIndexUsingComparinator(
|
||||
existingEntries,
|
||||
currentEntry,
|
||||
areEqualEntries,
|
||||
existingEntriesIteratorIndex
|
||||
);
|
||||
const hasEquivalentEntryInExistingEntries = indexInExistingEntries !== -1;
|
||||
|
||||
if (hasEquivalentEntryInExistingEntries) {
|
||||
// If the same entry exists in existing entries, we should add all of the entries that
|
||||
// come before to maintain order
|
||||
for (
|
||||
let j = existingEntriesIteratorIndex;
|
||||
j > indexInExistingEntries;
|
||||
j -= 1
|
||||
) {
|
||||
const existingEntry = existingEntries[j];
|
||||
|
||||
// If this entry also exists in new entries, we'll add as part of iterating through
|
||||
// new entries so that if there's a conflict between existing entries and new entries,
|
||||
// new entries order wins
|
||||
const hasMatchingEntryInNewEntries =
|
||||
findLastIndexUsingComparinator(
|
||||
newEntries,
|
||||
existingEntry,
|
||||
areEqualEntries,
|
||||
i
|
||||
) !== -1;
|
||||
|
||||
if (!hasMatchingEntryInNewEntries) {
|
||||
resultSet.unshift(existingEntry);
|
||||
}
|
||||
existingEntriesIteratorIndex -= 1;
|
||||
}
|
||||
|
||||
uniteEntries(currentEntry, existingEntries[existingEntriesIteratorIndex]);
|
||||
// uniteEntries mutates the second parameter to be a merged version, so that's what's pushed
|
||||
resultSet.unshift(existingEntries[existingEntriesIteratorIndex]);
|
||||
|
||||
existingEntriesIteratorIndex -= 1;
|
||||
} else {
|
||||
const alreadyHasMatchingEntryInResultSet =
|
||||
findLastIndexUsingComparinator(
|
||||
resultSet,
|
||||
currentEntry,
|
||||
areEqualEntries
|
||||
) !== -1;
|
||||
|
||||
if (!alreadyHasMatchingEntryInResultSet) {
|
||||
resultSet.unshift(currentEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add remaining existing entries
|
||||
for (
|
||||
existingEntriesIteratorIndex;
|
||||
existingEntriesIteratorIndex >= 0;
|
||||
existingEntriesIteratorIndex -= 1
|
||||
) {
|
||||
const existingEntry = existingEntries[existingEntriesIteratorIndex];
|
||||
const alreadyHasMatchingEntryInResultSet =
|
||||
findLastIndexUsingComparinator(resultSet, existingEntry, areEqualEntries) !==
|
||||
-1;
|
||||
|
||||
if (!alreadyHasMatchingEntryInResultSet) {
|
||||
resultSet.unshift(existingEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return resultSet;
|
||||
}
|
||||
|
||||
function findLastIndexUsingComparinator(
|
||||
entries,
|
||||
entryToFind,
|
||||
comparinator,
|
||||
startingIndex
|
||||
) {
|
||||
startingIndex = startingIndex || entries.length - 1;
|
||||
for (let i = startingIndex; i >= 0; i -= 1) {
|
||||
if (areEqualEntries(entryToFind, entries[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const { mergeWithCustomize } = require('webpack-merge');
|
||||
|
||||
module.exports.mergeSmart = mergeWithCustomize({
|
||||
customizeArray: (a, b, key) => {
|
||||
if (isRule(key.split('.').slice(-1)[0])) {
|
||||
return unionWith(a, b, uniteRules.bind(null, {}, key));
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
// Added by Mix to fix a regex merge bug
|
||||
customizeObject: (a, b, key) => {
|
||||
if (a instanceof RegExp) {
|
||||
if (b instanceof RegExp) {
|
||||
return b;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
if (b instanceof RegExp) {
|
||||
return b;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
let { mergeSmart } = require('./MergeSmart');
|
||||
|
||||
/** @typedef {import('webpack').Configuration} Configuration */
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Configuration} configA
|
||||
* @param {Configuration} configB
|
||||
*/
|
||||
module.exports = (configA, configB) => {
|
||||
return mergeSmart(configA, configB);
|
||||
};
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
let path = require('path');
|
||||
let Entry = require('./Entry');
|
||||
let webpackRules = require('./webpack-rules');
|
||||
let webpackPlugins = require('./webpack-plugins');
|
||||
let webpackDefaultConfig = require('./webpack-default');
|
||||
|
||||
class WebpackConfig {
|
||||
/**
|
||||
* Create a new instance.
|
||||
*
|
||||
* @param {import("../Mix.js")} mix
|
||||
*/
|
||||
constructor(mix) {
|
||||
this.mix = mix;
|
||||
this.chunks = mix.chunks;
|
||||
|
||||
/** @type {ReturnType<webpackDefaultConfig>} */
|
||||
this.webpackConfig = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Webpack configuration object.
|
||||
*/
|
||||
async build() {
|
||||
this.webpackConfig = webpackDefaultConfig(this.mix);
|
||||
|
||||
await this.buildEntry();
|
||||
this.buildOutput();
|
||||
this.configureHMR();
|
||||
await this.buildRules();
|
||||
await this.buildPlugins();
|
||||
this.buildChunks();
|
||||
|
||||
// We'll announce that the core config object has been
|
||||
// generated by Mix. At this point, any plugins may
|
||||
// hook in and modify the config as necessary.
|
||||
await this.mix.dispatch('configReady', this.webpackConfig);
|
||||
|
||||
// Rebuild the chunks as plugins may have added new ones
|
||||
this.buildChunks();
|
||||
|
||||
// Finally, we'll make one last announcement for the user
|
||||
// to hook into - using mix.override().
|
||||
await this.mix.dispatch('configReadyForUser', this.webpackConfig);
|
||||
|
||||
// Rebuild the chunks as the user may have changed things
|
||||
this.buildChunks();
|
||||
|
||||
return this.webpackConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the entry object.
|
||||
*/
|
||||
async buildEntry() {
|
||||
let entry = new Entry(this.mix);
|
||||
|
||||
if (!this.mix.bundlingJavaScript) {
|
||||
entry.addDefault();
|
||||
}
|
||||
|
||||
await this.mix.dispatch('loading-entry', entry);
|
||||
|
||||
this.webpackConfig.entry = entry.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the output object.
|
||||
*/
|
||||
buildOutput() {
|
||||
this.webpackConfig.output = {
|
||||
hashFunction: 'xxhash64',
|
||||
path: path.resolve(this.mix.config.publicPath),
|
||||
filename: '[name].js',
|
||||
|
||||
chunkFilename: pathData => {
|
||||
let hasAbsolutePathChunkName =
|
||||
pathData.chunk &&
|
||||
pathData.chunk.name &&
|
||||
pathData.chunk.name.startsWith('/');
|
||||
|
||||
if (
|
||||
(this.mix.components.get('js') || this.mix.components.get('ts')) &&
|
||||
!hasAbsolutePathChunkName
|
||||
) {
|
||||
let output = this.mix.components.get('ts')
|
||||
? this.mix.components.get('ts').toCompile[0].output
|
||||
: this.mix.components.get('js').toCompile[0].output;
|
||||
|
||||
return `${output.normalizedOutputPath()}/[name].js`;
|
||||
}
|
||||
|
||||
return '[name].js';
|
||||
},
|
||||
|
||||
publicPath: '/'
|
||||
};
|
||||
}
|
||||
|
||||
configureHMR() {
|
||||
if (!this.mix.isUsing('hmr')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { https, host, port } = this.mix.config.hmrOptions;
|
||||
const protocol = https ? 'https' : 'http';
|
||||
const url = `${protocol}://${host}:${port}/`;
|
||||
|
||||
this.webpackConfig.output = {
|
||||
...this.webpackConfig.output,
|
||||
|
||||
publicPath: url
|
||||
};
|
||||
|
||||
this.webpackConfig.devServer = {
|
||||
host,
|
||||
port,
|
||||
|
||||
client: {
|
||||
webSocketURL: {
|
||||
hostname: host,
|
||||
pathname: '/ws',
|
||||
port
|
||||
}
|
||||
},
|
||||
|
||||
liveReload: false,
|
||||
|
||||
https,
|
||||
|
||||
devMiddleware: {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Methods': 'GET, HEAD, OPTIONS',
|
||||
'Access-Control-Allow-Headers':
|
||||
'X-Requested-With, Content-Type, Authorization'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {{app: import("express").Application}} param0
|
||||
*/
|
||||
onBeforeSetupMiddleware({ app }) {
|
||||
app.use(function (req, _, next) {
|
||||
// Something causes hot update chunks (except for the JSON payload)
|
||||
// to start with a double slash
|
||||
// e.g. GET http://localhost:8080//js/app.[hash].hot-update.js
|
||||
|
||||
// This causes loading those chunks to fail so we patch it up here
|
||||
// This is super hacky and a proper solution should be found eventually
|
||||
req.url = req.url.replace(/^\/\//, '/');
|
||||
|
||||
next();
|
||||
});
|
||||
},
|
||||
|
||||
...this.webpackConfig.devServer
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the rules array.
|
||||
*/
|
||||
async buildRules() {
|
||||
this.webpackConfig.module = this.webpackConfig.module || {};
|
||||
this.webpackConfig.module.rules = this.webpackConfig.module.rules || [];
|
||||
|
||||
this.webpackConfig.module.rules.push(...webpackRules(this.mix));
|
||||
|
||||
await this.mix.dispatch('loading-rules', this.webpackConfig.module.rules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the plugins array.
|
||||
*/
|
||||
async buildPlugins() {
|
||||
this.webpackConfig.plugins = this.webpackConfig.plugins || [];
|
||||
this.webpackConfig.plugins.push(...webpackPlugins(this.mix));
|
||||
|
||||
await this.mix.dispatch('loading-plugins', this.webpackConfig.plugins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the resolve object.
|
||||
*/
|
||||
buildChunks() {
|
||||
this.webpackConfig = require('./MergeWebpackConfig')(
|
||||
this.webpackConfig,
|
||||
this.mix.chunks.config()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WebpackConfig;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
let path = require('path');
|
||||
let TerserPlugin = require('terser-webpack-plugin');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../Mix")} mix
|
||||
* @returns {import("webpack").Configuration & {devServer?: import("webpack").WebpackOptionsNormalized["devServer"]}}
|
||||
*/
|
||||
module.exports = function (mix) {
|
||||
// TODO: Remove in Mix 7 -- Here for backwards compat if a plugin requires this file
|
||||
mix = mix || global.Mix;
|
||||
|
||||
return {
|
||||
context: mix.paths.root(),
|
||||
|
||||
mode: mix.inProduction() ? 'production' : 'development',
|
||||
|
||||
infrastructureLogging: mix.isWatching() ? { level: 'none' } : {},
|
||||
|
||||
entry: {},
|
||||
|
||||
output: {
|
||||
chunkFilename: '[name].[hash:5].js'
|
||||
},
|
||||
|
||||
module: { rules: [] },
|
||||
|
||||
plugins: [],
|
||||
|
||||
resolve: {
|
||||
extensions: ['*', '.wasm', '.mjs', '.js', '.jsx', '.json'],
|
||||
roots: [path.resolve(mix.config.publicPath)]
|
||||
},
|
||||
|
||||
stats: {
|
||||
preset: 'errors-warnings',
|
||||
performance: mix.inProduction()
|
||||
},
|
||||
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
|
||||
optimization: mix.inProduction()
|
||||
? {
|
||||
providedExports: true,
|
||||
sideEffects: true,
|
||||
usedExports: true,
|
||||
// @ts-ignore
|
||||
minimizer: [new TerserPlugin(mix.config.terser)]
|
||||
}
|
||||
: {},
|
||||
|
||||
devtool: mix.config.sourcemaps,
|
||||
|
||||
// @ts-ignore
|
||||
devServer: {
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*'
|
||||
},
|
||||
static: path.resolve(mix.config.publicPath),
|
||||
historyApiFallback: true,
|
||||
compress: true,
|
||||
allowedHosts: 'all'
|
||||
},
|
||||
|
||||
watchOptions: {
|
||||
ignored: /node_modules/
|
||||
}
|
||||
};
|
||||
};
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
let MixDefinitionsPlugin = require('../webpackPlugins/MixDefinitionsPlugin');
|
||||
let BuildCallbackPlugin = require('../webpackPlugins/BuildCallbackPlugin');
|
||||
let CustomTasksPlugin = require('../webpackPlugins/CustomTasksPlugin');
|
||||
let ManifestPlugin = require('../webpackPlugins/ManifestPlugin');
|
||||
let MockEntryPlugin = require('../webpackPlugins/MockEntryPlugin');
|
||||
let BuildOutputPlugin = require('../webpackPlugins/BuildOutputPlugin');
|
||||
let WebpackBar = require('webpackbar');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {import("../Mix")} mix
|
||||
*/
|
||||
module.exports = function (mix) {
|
||||
// TODO: Remove in Mix 7 -- Here for backwards compat if a plugin requires this file
|
||||
mix = mix || global.Mix;
|
||||
|
||||
let plugins = [];
|
||||
|
||||
// If the user didn't declare any JS compilation, we still need to
|
||||
// use a temporary script to force a compile. This plugin will
|
||||
// handle the process of deleting the compiled script.
|
||||
if (!mix.bundlingJavaScript) {
|
||||
plugins.push(new MockEntryPlugin(mix));
|
||||
}
|
||||
|
||||
// Activate support for Mix_ .env definitions.
|
||||
plugins.push(
|
||||
new MixDefinitionsPlugin(mix.paths.root('.env'), {
|
||||
NODE_ENV: mix.inProduction()
|
||||
? 'production'
|
||||
: process.env.NODE_ENV || 'development'
|
||||
})
|
||||
);
|
||||
|
||||
// Handle the creation of the mix-manifest.json file.
|
||||
plugins.push(new ManifestPlugin(mix));
|
||||
|
||||
// Handle all custom, non-webpack tasks.
|
||||
plugins.push(new CustomTasksPlugin(mix));
|
||||
|
||||
// Notify the rest of our app when Webpack has finished its build.
|
||||
plugins.push(new BuildCallbackPlugin(stats => mix.dispatch('build', stats)));
|
||||
|
||||
// Enable custom output when the Webpack build completes.
|
||||
plugins.push(
|
||||
new BuildOutputPlugin({
|
||||
clearConsole: mix.config.clearConsole,
|
||||
showRelated: true
|
||||
})
|
||||
);
|
||||
|
||||
if (process.env.NODE_ENV !== 'test') {
|
||||
plugins.push(new WebpackBar({ name: 'Mix' }));
|
||||
}
|
||||
|
||||
return plugins;
|
||||
};
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
*
|
||||
* @param {import("../Mix")} mix
|
||||
*/
|
||||
module.exports = function (mix) {
|
||||
// TODO: Remove in Mix 7 -- Here for backwards compat if a plugin requires this file
|
||||
mix = mix || global.Mix;
|
||||
|
||||
/** @type {import("webpack").RuleSetRule[]} */
|
||||
let rules = [];
|
||||
|
||||
// Add support for loading HTML files.
|
||||
rules.push({
|
||||
test: /\.html$/,
|
||||
resourceQuery: { not: [/\?vue/i] },
|
||||
use: [{ loader: mix.resolve('html-loader') }]
|
||||
});
|
||||
|
||||
if (mix.config.imgLoaderOptions) {
|
||||
// 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|webp|avif)$|^((?!font).)*\.svg$)/,
|
||||
use: [
|
||||
{
|
||||
loader: mix.resolve('file-loader'),
|
||||
options: {
|
||||
/**
|
||||
* @param {string} path
|
||||
*/
|
||||
name: path => {
|
||||
if (!/node_modules|bower_components/.test(path)) {
|
||||
return (
|
||||
mix.config.fileLoaderDirs.images +
|
||||
'/[name].[ext]?[hash]'
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
mix.config.fileLoaderDirs.images +
|
||||
'/vendor/' +
|
||||
path
|
||||
.replace(/\\/g, '/')
|
||||
.replace(
|
||||
/((.*(node_modules|bower_components))|images|image|img|assets)\//g,
|
||||
''
|
||||
) +
|
||||
'?[hash]'
|
||||
);
|
||||
},
|
||||
publicPath: mix.config.resourceRoot
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
loader: mix.resolve('img-loader'),
|
||||
options: mix.config.imgLoaderOptions || {}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// Add support for loading fonts.
|
||||
rules.push({
|
||||
test: /(\.(woff2?|ttf|eot|otf)$|font.*\.svg$)/,
|
||||
use: [
|
||||
{
|
||||
loader: mix.resolve('file-loader'),
|
||||
options: {
|
||||
/**
|
||||
* @param {string} path
|
||||
*/
|
||||
name: path => {
|
||||
if (!/node_modules|bower_components/.test(path)) {
|
||||
return (
|
||||
mix.config.fileLoaderDirs.fonts + '/[name].[ext]?[hash]'
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
mix.config.fileLoaderDirs.fonts +
|
||||
'/vendor/' +
|
||||
path
|
||||
.replace(/\\/g, '/')
|
||||
.replace(
|
||||
/((.*(node_modules|bower_components))|fonts|font|assets)\//g,
|
||||
''
|
||||
) +
|
||||
'?[hash]'
|
||||
);
|
||||
},
|
||||
publicPath: mix.config.resourceRoot
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// Add support for loading cursor files.
|
||||
rules.push({
|
||||
test: /\.(cur|ani)$/,
|
||||
use: [
|
||||
{
|
||||
loader: mix.resolve('file-loader'),
|
||||
options: {
|
||||
name: '[name].[ext]?[hash]',
|
||||
publicPath: mix.config.resourceRoot
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
return rules;
|
||||
};
|
||||
Reference in New Issue
Block a user