UNPKG

@apployees-nx/webserver

Version:

A create-react-app inspired plugin for Nx, with SSR and PWA capabilities.

233 lines (224 loc) 9.01 kB
/******************************************************************************* * © Apployees Inc., 2019 * All Rights Reserved. ******************************************************************************/ import { IBuildWebserverBuilderOptions } from "../common/webserver-types"; import { getAssetsUrl } from "../common/env"; import postcssNormalize from "postcss-normalize"; import { cssModuleRegex, cssRegex, getCSSModuleLocalIdent, lessModuleRegex, lessRegex, sassModuleRegex, sassRegex, } from "../common/common-loaders"; import _ from "lodash"; import MiniCssExtractPlugin from "mini-css-extract-plugin"; import NodeSass from "node-sass"; export function getClientLoaders(options: IBuildWebserverBuilderOptions) { const isEnvDevelopment: boolean = options.dev; const isEnvProduction = !isEnvDevelopment; const shouldUseSourceMap = isEnvDevelopment && options.sourceMapForStyles; // Webpack uses `publicPath` to determine where the app is being served from. // It requires a trailing slash, or the file assets will get an incorrect path. // In development, we always serve from the root. This makes config easier. const publicPath = getAssetsUrl(options); // Some apps do not use client-side routing with pushState. // For these, "homepage" can be set to "." to enable relative asset paths. const shouldUseRelativeAssetPaths = publicPath.startsWith("."); let styleOrExtractLoader; if (isEnvDevelopment) { styleOrExtractLoader = _.isString(require.resolve("style-loader")) ? require.resolve("style-loader") : "style-loader"; } else { styleOrExtractLoader = { loader: MiniCssExtractPlugin.loader, // css is located in `static/css`, use '../../' to locate index.html folder // in production `paths.publicUrlOrPath` can be a relative path options: shouldUseRelativeAssetPaths ? { publicPath: "../../" } : {}, }; } // common function to get style loaders const getStyleLoaders = (isForModule: boolean, cssOptions?) => { cssOptions = isForModule ? { ...cssOptions, localsConvention: "dashesOnly", modules: { localIdentName: getCSSModuleLocalIdent(isEnvDevelopment), }, } : cssOptions; return [ // For some reason, webpack is unable to load the CSS // files that are extracted from this MiniCssExtractPlugin // Therefore, for now, we are going to use style-loader regardless of dev or production mode, // and comment out MiniCssExtractPlugin styleOrExtractLoader, { loader: _.isString(require.resolve("css-loader")) ? require.resolve("css-loader") : "css-loader", options: { ...cssOptions, sourceMap: shouldUseSourceMap, }, }, { // Options for PostCSS as we reference these options twice // Adds vendor prefixing based on your specified browser support in // package.json loader: _.isString(require.resolve("postcss-loader")) ? require.resolve("postcss-loader") : "postcss-loader", options: { // Necessary for external CSS imports to work // https://github.com/facebook/create-react-app/issues/2677 ident: "postcss", plugins: () => [ require("postcss-flexbugs-fixes"), require("postcss-preset-env")({ autoprefixer: { flexbox: "no-2009", }, stage: 3, }), // Adds PostCSS Normalize as the reset css with default options, // so that it honors browserslist config in package.json // which in turn let's users customize the target behavior as per their needs. postcssNormalize(), ], sourceMap: shouldUseSourceMap, }, }, ].filter(Boolean); }; return [ // "url" loader works like "file" loader except that it embeds assets // smaller than specified limit in bytes as data URLs to avoid requests. // A missing `test` is equivalent to a match. { test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.woff$/, /\.woff2$/, /\.avi$/, /\.mp4$/, /\.mp3$/], loader: _.isString(require.resolve("url-loader")) ? require.resolve("url-loader") : "url-loader", options: { limit: options.imageInlineSizeLimit, name: "static/media/[name].[hash:8].[ext]", }, }, // "postcss" loader applies autoprefixer to our CSS. // "css" loader resolves paths in CSS and adds assets as dependencies. // "style" loader turns CSS into JS modules that inject <style> tags. // In production, we use MiniCSSExtractPlugin to extract that CSS // to a file, but in development "style" loader enables hot editing // of CSS. // By default we support CSS Modules with the extension .module.css { test: cssRegex, exclude: cssModuleRegex, use: getStyleLoaders(false, { importLoaders: 1, sourceMap: shouldUseSourceMap, }), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. // Remove this when webpack adds a warning or an error for this. // See https://github.com/webpack/webpack/issues/6571 sideEffects: true, }, // Adds support for CSS Modules (https://github.com/css-modules/css-modules) // using the extension .module.css { test: cssModuleRegex, use: getStyleLoaders(true, { importLoaders: 1, }), }, // Opt-in support for SASS (using .scss or .sass extensions). // By default we support SASS Modules with the // extensions .module.scss or .module.sass { test: sassRegex, exclude: sassModuleRegex, use: getStyleLoaders(false, { importLoaders: 2, }).concat({ loader: _.isString(require.resolve("sass-loader")) ? require.resolve("sass-loader") : "sass-loader", options: { implementation: NodeSass, sourceMap: shouldUseSourceMap, }, }), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. // Remove this when webpack adds a warning or an error for this. // See https://github.com/webpack/webpack/issues/6571 sideEffects: true, }, // Adds support for CSS Modules, but using SASS // using the extension .module.scss or .module.sass { test: sassModuleRegex, use: getStyleLoaders(true, { importLoaders: 2, }).concat({ loader: _.isString(require.resolve("sass-loader")) ? require.resolve("sass-loader") : "sass-loader", options: { implementation: NodeSass, sourceMap: shouldUseSourceMap, }, }), }, // Opt-in support for LESS (using .less). // By default we support LESS Modules with the // extensions .module.LESS { test: lessRegex, exclude: lessModuleRegex, use: getStyleLoaders(false, { importLoaders: 2, }).concat({ loader: _.isString(require.resolve("less-loader")) ? require.resolve("less-loader") : "less-loader", options: { sourceMap: shouldUseSourceMap, javascriptEnabled: true, modifyVars: options.lessStyleVariables_calculated, }, }), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. // Remove this when webpack adds a warning or an error for this. // See https://github.com/webpack/webpack/issues/6571 sideEffects: true, }, // Adds support for CSS Modules, but using less // using the extension .module.less { test: lessModuleRegex, use: getStyleLoaders(true, { importLoaders: 2, }).concat({ loader: _.isString(require.resolve("less-loader")) ? require.resolve("less-loader") : "less-loader", options: { sourceMap: shouldUseSourceMap, javascriptEnabled: true, modifyVars: options.lessStyleVariables_calculated, }, }), }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. // This loader doesn't use a "test" so it will catch all modules // that fall through the other loaders. { loader: _.isString(require.resolve("file-loader")) ? require.resolve("file-loader") : "file-loader", // Exclude `js` files to keep "css" loader working as it injects // its runtime that would otherwise be processed through "file" loader. // Also exclude `html` and `json` extensions so they get processed // by webpacks internal loaders. exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], options: { name: "static/media/[name].[hash:8].[ext]", }, }, ]; }