mirror of
https://github.com/strapi/strapi.git
synced 2025-07-15 13:02:42 +00:00
342 lines
11 KiB
JavaScript
Executable File
342 lines
11 KiB
JavaScript
Executable File
/**
|
|
* COMMON WEBPACK CONFIGURATION
|
|
*/
|
|
|
|
/* eslint-disable no-console */
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const webpack = require('webpack');
|
|
const _ = require('lodash');
|
|
|
|
const pkg = require(path.resolve(process.cwd(), 'package.json'));
|
|
const pluginId = pkg.name.replace(/^strapi-/i, '');
|
|
const isAdmin = process.env.IS_ADMIN === 'true';
|
|
|
|
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
|
|
|
const appPath = (() => {
|
|
if (process.env.APP_PATH) {
|
|
return process.env.APP_PATH;
|
|
}
|
|
|
|
return isAdmin ? path.resolve(process.env.PWD, '..') : path.resolve(process.env.PWD, '..', '..');
|
|
})();
|
|
// const isSetup = path.resolve(process.env.PWD, '..', '..') === path.resolve(process.env.INIT_CWD);
|
|
const isSetup = process.env.IS_MONOREPO;
|
|
|
|
const adminPath = (() => {
|
|
if (isAdmin && isSetup) {
|
|
return path.resolve(appPath, 'strapi-admin');
|
|
}
|
|
|
|
return path.resolve(process.env.PWD);
|
|
})();
|
|
|
|
// Define remote and backend URLs.
|
|
const URLs = {
|
|
host: '/admin',
|
|
backend: '/',
|
|
publicPath: null,
|
|
mode: 'host',
|
|
};
|
|
|
|
if (isAdmin && !isSetup) {
|
|
// Load server configuration.
|
|
const serverConfig = path.resolve(
|
|
appPath,
|
|
'config',
|
|
'environments',
|
|
_.lowerCase(process.env.NODE_ENV),
|
|
'server.json',
|
|
);
|
|
|
|
try {
|
|
const server = require(serverConfig);
|
|
|
|
if (process.env.PWD.indexOf('/admin') !== -1) {
|
|
if (_.get(server, 'admin.build.host')) {
|
|
URLs.host = _.get(server, 'admin.build.host', '/admin').replace(/\/$/, '') || '/';
|
|
} else {
|
|
URLs.host = _.get(server, 'admin.path', '/admin');
|
|
}
|
|
|
|
URLs.publicPath = URLs.host;
|
|
URLs.backend = _.get(server, 'admin.build.backend', `/`);
|
|
|
|
if (_.get(server, 'admin.build.plugins.source') === 'backend') {
|
|
URLs.mode = 'backend';
|
|
}
|
|
|
|
if (process.env.npm_lifecycle_event === 'start') {
|
|
URLs.backend = `http://${_.get(server, 'host', 'localhost')}:${_.get(server, 'port', 1337)}`;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
throw new Error(`Impossible to access to ${serverConfig}`);
|
|
}
|
|
}
|
|
|
|
// Load plugins into the same build in development mode.
|
|
const plugins = {
|
|
exist: false,
|
|
src: [],
|
|
folders: {},
|
|
};
|
|
|
|
if (process.env.npm_lifecycle_event === 'start') {
|
|
try {
|
|
fs.accessSync(path.resolve(appPath, 'plugins'), fs.constants.R_OK);
|
|
} catch (e) {
|
|
// Allow app without plugins.
|
|
plugins.exist = true;
|
|
}
|
|
|
|
// Read `plugins` directory and check if the plugin comes with an UI (it has an App container).
|
|
// If we don't do this check webpack expects the plugin to have a containers/App/reducer.js to create
|
|
// the plugin's store (redux).
|
|
plugins.src =
|
|
isAdmin && !plugins.exist
|
|
? fs.readdirSync(path.resolve(appPath, 'plugins')).filter(x => {
|
|
let hasAdminFolder;
|
|
|
|
try {
|
|
fs.accessSync(path.resolve(appPath, 'plugins', x, 'admin', 'src', 'containers', 'App'));
|
|
hasAdminFolder = true;
|
|
} catch (err) {
|
|
hasAdminFolder = false;
|
|
}
|
|
return x[0] !== '.' && hasAdminFolder;
|
|
})
|
|
: [];
|
|
|
|
// Construct object of plugin' paths.
|
|
plugins.folders = plugins.src.reduce((acc, current) => {
|
|
acc[current] = path.resolve(
|
|
appPath,
|
|
'plugins',
|
|
current,
|
|
'node_modules',
|
|
'strapi-helper-plugin',
|
|
'lib',
|
|
'src',
|
|
);
|
|
|
|
return acc;
|
|
}, {});
|
|
}
|
|
|
|
// Tell webpack to use a loader only for those files
|
|
const foldersToInclude = [path.join(adminPath, 'admin', 'src')]
|
|
.concat(
|
|
plugins.src.reduce((acc, current) => {
|
|
acc.push(path.resolve(appPath, 'plugins', current, 'admin', 'src'), plugins.folders[current]);
|
|
|
|
return acc;
|
|
}, []),
|
|
)
|
|
.concat([path.join(adminPath, 'node_modules', 'strapi-helper-plugin', 'lib', 'src')]);
|
|
|
|
module.exports = options => {
|
|
// The disable option is only for production
|
|
// Config from https://github.com/facebook/create-react-app/blob/next/packages/react-scripts/config/webpack.config.prod.js
|
|
const extractSass = new ExtractTextPlugin({
|
|
filename: '[name].[contenthash].css',
|
|
disable: options.disableExtractTextPlugin || true,
|
|
});
|
|
|
|
return {
|
|
entry: options.entry,
|
|
output: Object.assign(
|
|
{
|
|
// Compile into js/build.js
|
|
path: path.join(adminPath, 'admin', 'build'),
|
|
},
|
|
options.output,
|
|
), // Merge with env dependent settings
|
|
module: {
|
|
rules: [
|
|
// TODO: add eslint formatter
|
|
{
|
|
// "oneOf" will traverse all following loaders until one will
|
|
// match the requirements. When no loader matches it will fall
|
|
// back to the "file" loader at the end of the loader list.
|
|
oneOf: [
|
|
{
|
|
test: /\.js$/, // Transform all .js files required somewhere with Babel,
|
|
loader: require.resolve('babel-loader'),
|
|
include: foldersToInclude,
|
|
options: {
|
|
presets: options.babelPresets,
|
|
env: {
|
|
production: {
|
|
only: ['src'],
|
|
plugins: [
|
|
require.resolve('babel-plugin-transform-react-remove-prop-types'),
|
|
require.resolve('babel-plugin-transform-react-constant-elements'),
|
|
require.resolve('babel-plugin-transform-react-inline-elements'),
|
|
require.resolve('babel-plugin-transform-es2015-destructuring'),
|
|
require.resolve('babel-plugin-transform-es2015-parameters'),
|
|
require.resolve('babel-plugin-transform-object-rest-spread'),
|
|
[require.resolve('babel-plugin-styled-components'), { ssr: true, preprocess: true }],
|
|
],
|
|
},
|
|
test: {
|
|
plugins: ['istanbul'],
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// The notation here is somewhat confusing.
|
|
// "postcss" loader applies autoprefixer to our CSS.
|
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
|
// "style" loader normally turns CSS into JS modules injecting <style>,
|
|
// but unlike in development configuration, we do something different.
|
|
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
|
|
// (second argument), then grabs the result CSS and puts it into a
|
|
// separate file in our build process. This way we actually ship
|
|
// a single CSS file in production instead of JS code injecting <style>
|
|
// tags. If you use code splitting, however, any async bundles will still
|
|
// use the "style" loader inside the async code so CSS from them won't be
|
|
// in the main CSS file.
|
|
{
|
|
test: /\.css$/,
|
|
include: /node_modules/,
|
|
use: extractSass.extract({
|
|
fallback: require.resolve('style-loader'),
|
|
use: [
|
|
{
|
|
loader: require.resolve('css-loader'),
|
|
options: {
|
|
minimize: process.env.NODE_ENV === 'production',
|
|
sourceMap: false,
|
|
},
|
|
},
|
|
{
|
|
loader: require.resolve('postcss-loader'),
|
|
options: {
|
|
config: {
|
|
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
|
},
|
|
},
|
|
},
|
|
],
|
|
}),
|
|
},
|
|
{
|
|
test: /\.scss$/,
|
|
include: foldersToInclude,
|
|
use: extractSass.extract({
|
|
use: [
|
|
{
|
|
loader: require.resolve('css-loader'),
|
|
options: {
|
|
localIdentName: `${pluginId}[local]__[path][name]__[hash:base64:5]`,
|
|
modules: true,
|
|
importLoaders: 1,
|
|
sourceMap: false,
|
|
minimize: process.env.NODE_ENV === 'production',
|
|
},
|
|
},
|
|
{
|
|
loader: require.resolve('postcss-loader'),
|
|
options: {
|
|
config: {
|
|
path: path.resolve(__dirname, '..', 'postcss', 'postcss.config.js'),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
loader: 'sass-loader',
|
|
},
|
|
],
|
|
fallback: require.resolve('style-loader'),
|
|
}),
|
|
},
|
|
{
|
|
test: /\.(eot|svg|otf|ttf|woff|woff2)$/,
|
|
use: 'file-loader',
|
|
},
|
|
{
|
|
test: /\.(jpg|png|gif)$/,
|
|
loaders: [
|
|
require.resolve('file-loader'),
|
|
{
|
|
loader: require.resolve('image-webpack-loader'),
|
|
query: {
|
|
mozjpeg: {
|
|
progressive: true,
|
|
},
|
|
gifsicle: {
|
|
interlaced: false,
|
|
},
|
|
optipng: {
|
|
optimizationLevel: 4,
|
|
},
|
|
pngquant: {
|
|
quality: '65-90',
|
|
speed: 4,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
test: /\.html$/,
|
|
include: [path.join(adminPath, 'admin', 'src')],
|
|
use: require.resolve('html-loader'),
|
|
},
|
|
{
|
|
test: /\.(mp4|webm)$/,
|
|
loader: require.resolve('url-loader'),
|
|
options: {
|
|
limit: 10000,
|
|
},
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
plugins: [
|
|
new webpack.ProvidePlugin({
|
|
// make fetch available
|
|
fetch: 'exports-loader?self.fetch!whatwg-fetch',
|
|
}),
|
|
|
|
// Always expose NODE_ENV to webpack, in order to use `process.env.NODE_ENV`
|
|
// inside your code for any environment checks; UglifyJS will automatically
|
|
// drop any unreachable code.
|
|
new webpack.DefinePlugin({
|
|
'process.env': {
|
|
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
|
|
REMOTE_URL: JSON.stringify(URLs.host),
|
|
BACKEND_URL: JSON.stringify(URLs.backend),
|
|
MODE: JSON.stringify(URLs.mode), // Allow us to define the public path for the plugins assets.
|
|
},
|
|
}),
|
|
new webpack.NamedModulesPlugin(),
|
|
extractSass,
|
|
].concat(options.plugins),
|
|
resolve: {
|
|
modules: [
|
|
'admin/src',
|
|
'node_modules/strapi-helper-plugin/lib/src',
|
|
'node_modules/strapi-helper-plugin/node_modules',
|
|
'node_modules',
|
|
],
|
|
alias: options.alias,
|
|
symlinks: false,
|
|
extensions: ['.js', '.jsx', '.react.js'],
|
|
mainFields: ['browser', 'jsnext:main', 'main'],
|
|
},
|
|
externals: options.externals,
|
|
resolveLoader: {
|
|
modules: [
|
|
path.join(__dirname, '..', '..', '..', 'node_modules'),
|
|
path.join(process.cwd(), 'node_modules'),
|
|
],
|
|
},
|
|
devtool: options.devtool,
|
|
target: 'web', // Make web variables accessible to webpack, e.g. window,
|
|
};
|
|
};
|