2018-05-18 14:22:24 +02:00

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,
};
};