From e896af232cd046505f5633e0150b2eac89ddc4a2 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 2 Dec 2021 21:26:42 +0200 Subject: [PATCH 01/37] replace existing skeleton with basic pota implementation --- .browserslistrc | 9 - .pota/commands/build.js | 12 + .pota/config.js | 5 + .pota/webpack/plugins/MubanPagePlugin.js | 70 + .pota/webpack/webpack.config.js | 207 + .prettierignore | 1 - .prettierrc | 21 - .storybook/main.cjs | 41 + .storybook/main.ts | 22 - .storybook/manager.js | 6 + .storybook/mm-theme.js | 8 + .storybook/package.json | 1 + .storybook/preview.js | 12 +- .storybook/static/mm-theme-brand-logo.png | Bin 0 -> 10942 bytes .storybook/webpack.config.ts | 65 - README.md | 181 +- STATUS.MD | 77 - babel.config.js | 172 - config/env.ts | 97 - config/paths.ts | 68 - config/tsconfig.webpack.json | 8 - config/webpack.config.ts | 478 - deploy-docs.sh | 28 - mocks/products/abc.json | 6 - mocks/products/default.json | 6 - mocks/user.ts | 43 - package-lock.json | 47387 ++++++++++++++++ package.json | 141 +- patches/cjs-entry.patch | 18 + patches/name-check.patch | 18 + patches/story-context.patch | 29 + scripts/devserver/devserver.ts | 118 - scripts/devserver/formatWebpackMessages.ts | 123 - scripts/devserver/getHttpsConfig.ts | 72 - scripts/devserver/getServerBundle.ts | 103 - scripts/devserver/utils.ts | 194 - scripts/devserver/webpack.config.ts | 84 - scripts/devserver/webpackDevServer.config.ts | 171 - scripts/generateTemplates.ts | 120 - scripts/mocks/generateMockPackageJson.ts | 43 - scripts/mocks/index.ts | 3 - scripts/mocks/tsconfig.mocks.json | 13 - scripts/preview-server.ts | 77 - scripts/tsconfig.json | 14 - scripts/utils.ts | 110 - src/App.ts | 2 + src/assets.d.ts | 20 + .../atoms/cf-a2-icon/CfA2Icon.config.ts | 10 - src/components/atoms/cf-a2-icon/CfA2Icon.ts | 15 +- .../toggle-expand/ToggleExpand.stories.ts | 1 + .../toggle-expand/ToggleExpand.template.ts | 3 +- src/components/image-test/ImageTest.mocks.ts | 3 +- .../image-test/ImageTest.stories.ts | 5 +- .../image-test/ImageTest.template.ts | 5 +- src/components/image-test/ImageTest.ts | 4 +- src/components/video-test/VideoTest.mocks.ts | 3 +- .../video-test/VideoTest.stories.ts | 5 +- .../video-test/VideoTest.template.ts | 5 +- src/{index.ts => main.ts} | 0 src/pages/image-test.ts | 2 +- src/pages/main.ts | 11 + src/pages/public/favicon.ico | Bin 0 -> 1151 bytes .../devserver => src/pages/public}/index.html | 4 +- .../static/img}/mock-test.jpg | Bin .../static/media}/dummy-video-1.mp4 | Bin src/pages/static/readme.md | 5 - src/pages/video-test.ts | 2 +- src/polyfills.js | 3 - src/public/readme.md | 6 - src/public/static/readme.md | 8 - src/server-bundle.ts | 18 - src/types.d.ts | 4 - .../preview-head.html => static/.gitkeep | 0 .../images => static/img}/template-test.jpg | Bin svgo.config.js | 6 - tsconfig.json | 52 - yarn.lock | 15179 ----- 77 files changed, 48048 insertions(+), 17815 deletions(-) delete mode 100644 .browserslistrc create mode 100644 .pota/commands/build.js create mode 100644 .pota/config.js create mode 100644 .pota/webpack/plugins/MubanPagePlugin.js create mode 100644 .pota/webpack/webpack.config.js delete mode 100644 .prettierignore delete mode 100644 .prettierrc create mode 100644 .storybook/main.cjs delete mode 100644 .storybook/main.ts create mode 100644 .storybook/manager.js create mode 100644 .storybook/mm-theme.js create mode 100644 .storybook/package.json create mode 100644 .storybook/static/mm-theme-brand-logo.png delete mode 100644 .storybook/webpack.config.ts delete mode 100644 STATUS.MD delete mode 100644 babel.config.js delete mode 100644 config/env.ts delete mode 100644 config/paths.ts delete mode 100644 config/tsconfig.webpack.json delete mode 100644 config/webpack.config.ts delete mode 100755 deploy-docs.sh delete mode 100644 mocks/products/abc.json delete mode 100644 mocks/products/default.json delete mode 100644 mocks/user.ts create mode 100644 package-lock.json create mode 100644 patches/cjs-entry.patch create mode 100644 patches/name-check.patch create mode 100644 patches/story-context.patch delete mode 100644 scripts/devserver/devserver.ts delete mode 100644 scripts/devserver/formatWebpackMessages.ts delete mode 100644 scripts/devserver/getHttpsConfig.ts delete mode 100644 scripts/devserver/getServerBundle.ts delete mode 100644 scripts/devserver/utils.ts delete mode 100644 scripts/devserver/webpack.config.ts delete mode 100644 scripts/devserver/webpackDevServer.config.ts delete mode 100644 scripts/generateTemplates.ts delete mode 100644 scripts/mocks/generateMockPackageJson.ts delete mode 100644 scripts/mocks/index.ts delete mode 100644 scripts/mocks/tsconfig.mocks.json delete mode 100644 scripts/preview-server.ts delete mode 100644 scripts/tsconfig.json delete mode 100644 scripts/utils.ts create mode 100644 src/assets.d.ts delete mode 100644 src/components/atoms/cf-a2-icon/CfA2Icon.config.ts rename src/{index.ts => main.ts} (100%) create mode 100644 src/pages/main.ts create mode 100755 src/pages/public/favicon.ico rename {scripts/devserver => src/pages/public}/index.html (71%) mode change 100644 => 100755 rename src/pages/{static/images => public/static/img}/mock-test.jpg (100%) rename src/pages/{static/video => public/static/media}/dummy-video-1.mp4 (100%) delete mode 100644 src/pages/static/readme.md delete mode 100644 src/polyfills.js delete mode 100644 src/public/readme.md delete mode 100644 src/public/static/readme.md delete mode 100644 src/server-bundle.ts delete mode 100644 src/types.d.ts rename .storybook/preview-head.html => static/.gitkeep (100%) rename {src/public/static/images => static/img}/template-test.jpg (100%) delete mode 100644 svgo.config.js delete mode 100644 tsconfig.json delete mode 100644 yarn.lock diff --git a/.browserslistrc b/.browserslistrc deleted file mode 100644 index 634aba4..0000000 --- a/.browserslistrc +++ /dev/null @@ -1,9 +0,0 @@ -# Browsers that we support - -# defaults # > 0.5%, last 2 versions, Firefox ESR, not dead - -last 3 versions -last 3 iOS versions -not IE 11 # remove `not` to support IE 11 -not dead # hide dead browsers -> 5% # include if this is used by a lot of people, even though not in the above records diff --git a/.pota/commands/build.js b/.pota/commands/build.js new file mode 100644 index 0000000..1773fc4 --- /dev/null +++ b/.pota/commands/build.js @@ -0,0 +1,12 @@ +import { options as webpackSkeletonOptions } from "@pota/webpack-skeleton/.pota/commands/build.js" + +export { description, action } from "@pota/webpack-skeleton/.pota/commands/build.js" + +export const options = [ + ...webpackSkeletonOptions, + { + option: '--preview', + description: 'Toggles support for building the preview', + }, +]; + diff --git a/.pota/config.js b/.pota/config.js new file mode 100644 index 0000000..3905407 --- /dev/null +++ b/.pota/config.js @@ -0,0 +1,5 @@ +export default { + extends: "@pota/webpack-skeleton", + scripts: ["build", "storybook", "storybook:build", "apply-storybook-patches"], + omit: ["public"] +}; diff --git a/.pota/webpack/plugins/MubanPagePlugin.js b/.pota/webpack/plugins/MubanPagePlugin.js new file mode 100644 index 0000000..2048081 --- /dev/null +++ b/.pota/webpack/plugins/MubanPagePlugin.js @@ -0,0 +1,70 @@ +import { readFile } from "fs/promises"; +import requireFromString from "require-from-string"; + +const NS = "MubanPagePlugin"; + +let cachedTemplate; + +async function getHTMLTemplate(path) { + cachedTemplate = cachedTemplate ?? (await readFile(path, { encoding: "utf-8" })); + return cachedTemplate; +} + +function replaceTemplateVars(template, variables = {}) { + let updatedTemplate = String(template); + + for (const [key, value] of Object.entries(variables)) { + updatedTemplate = updatedTemplate.replace(new RegExp(`{{${key}}}`, "g"), value); + } + + return updatedTemplate; +} + +export default class MubanPagePlugin { + options; + + constructor(options) { + this.options = options; + } + + apply(compiler) { + const { webpack } = compiler; + const { sources, Compilation } = webpack; + + // Specify the event hook to attach to + compiler.hooks.thisCompilation.tap(NS, (compilation) => { + compilation.hooks.processAssets.tapPromise( + { name: NS, stage: Compilation.PROCESS_ASSETS_STAGE_DERIVED }, + async () => { + const [chunk] = compilation.chunks; + const [file] = chunk.files; + + const source = compilation.getAsset(file).source.source(); + + const { pages, appTemplate } = requireFromString(source); + + const compilationHash = compilation.hash; + + const publicPath = compilation.getAssetPath(compilation.outputOptions.publicPath, { + hash: compilationHash, + }); + + const htmlTemplate = await getHTMLTemplate(this.options.template); + + for (const [page, pageModule] of Object.entries(pages)) { + if (!pageModule || !("data" in pageModule)) continue; + + const pageTemplate = replaceTemplateVars(htmlTemplate, { + content: appTemplate(pageModule.data()), + publicPath, + }); + + compilation.emitAsset(`${page}.html`, new sources.RawSource(pageTemplate)); + } + + compilation.deleteAsset(file); + } + ); + }); + } +} diff --git a/.pota/webpack/webpack.config.js b/.pota/webpack/webpack.config.js new file mode 100644 index 0000000..9509b4a --- /dev/null +++ b/.pota/webpack/webpack.config.js @@ -0,0 +1,207 @@ +import { join, resolve } from "path"; +import historyApiFallback from "connect-history-api-fallback"; +import * as paths from "@pota/webpack-skeleton/.pota/webpack/paths.js"; +import { createFindPlugin } from "@pota/webpack-skeleton/.pota/webpack/util.js"; +import MubanPagePlugin from "./plugins/MubanPagePlugin.js"; +import MiniCssExtractPlugin from "mini-css-extract-plugin"; +import CopyPlugin from "copy-webpack-plugin"; + +const CSS_TEST = /\.css$/; +const SCSS_TEST = /\.(scss|sass)$/; + +function isString(value) { + return typeof value === "string"; +} + +function createMainConfig(config, { mainName, pagesName }) { + let { plugins } = config; + + const isDev = config.mode + ? config.mode === "development" + : process.env.NODE_ENV === "development"; + + const findPlugin = createFindPlugin(config); + const htmlPlugin = findPlugin("HtmlWebpackPlugin"); + const copyPlugin = findPlugin("CopyPlugin"); + + plugins = plugins.filter((plugin) => plugin !== htmlPlugin && plugin !== copyPlugin); + + /** @type {import('webpack').Configuration} */ + return { + ...config, + name: mainName, + output: { + ...config.output, + filename: `static/chunks/[name].js`, + }, + optimization: { + ...config.optimization, + runtimeChunk: undefined, + splitChunks: { + ...config.splitChunks, + cacheGroups: { + ...config.cacheGroups, + // but Muban is special and requires a single `main.css` file 😁 + styles: { + name: "main", + type: "css/mini-extract", + chunks: "all", + enforce: true, + }, + }, + }, + }, + module: { + ...config.module, + // this overriding of `style-loader` to `MiniCssExtractPlugin.loader` would happen only during production + // but Muban is special and requires a single `main.css` file 😁 + rules: config.module.rules.map((rule) => { + if ([String(CSS_TEST), String(SCSS_TEST)].includes(String(rule.test))) { + return { + ...rule, + use: rule.use.map((use) => { + if (use === "style-loader") return MiniCssExtractPlugin.loader; + if (!isString(use) && "loader" in use && use.loader === "sass-loader") { + return { + ...use, + options: { + ...use.options, + // TODO: this is terribly inefficient, since we're creating a single .css file there should be a better way to add global styles + additionalData: ` + @import "~seng-scss"; + @import "@/styles/_global.scss"; + `, + }, + }; + } + return use; + }), + }; + } + + return rule; + }), + }, + devServer: { + ...config.devServer, + static: { + ...config.devServer.static, + serveIndex: false, + }, + historyApiFallback: false, + onBeforeSetupMiddleware(devServer) { + if (!devServer) { + throw new Error("[onBeforeSetupMiddleware]: `devServer` is not defined"); + } + + devServer.app.use("/", (req, res, next) => { + if (!devServer.stats) return next(); + + // find all of the `.html` assets generated by the "pages" compilation (the other config) + const pageAssets = Array.from( + devServer.stats.stats.find(({ compilation }) => compilation.name === pagesName) + .compilation.emittedAssets + ).filter((asset) => asset.endsWith(".html")); + + // setup redirects from paths to html files e.g. `/my/favourite/page` to `/my/favourite/page.html` + return historyApiFallback({ + rewrites: pageAssets.map((asset) => ({ + from: new RegExp(`^\/${asset.replace(".html", "").replace("/index", "")}$`), + to: `/${asset}`, + })), + })(req, res, next); + }); + }, + }, + plugins: [ + ...plugins, + // this plugin is generally applied only during production builds, but Muban is special and requires a single `main.css` file 😁 + new MiniCssExtractPlugin({ + ignoreOrder: true, + filename: "static/css/[name].css", + chunkFilename: `static/css/${isDev ? "[id]" : "[id].[contenthash]"}.css`, + }), + new CopyPlugin({ + patterns: [ + { + from: "static", + to: `static`, + noErrorOnMissing: true, + globOptions: { ignore: ["**/.*"] }, + }, + ], + }), + ], + }; +} + +function createPagesConfig(config, { mainName, pagesName }) { + const definePlugin = createFindPlugin(config)("DefinePlugin"); + + const source = join(paths.source, "./pages"); + const publicDir = join(source, "./public"); + + /** @type {import('webpack').Configuration} */ + return { + ...config, + mode: "development", // we do not care about the size of the output, it just needs to be built fast + devtool: false, // source maps will not be used + name: pagesName, // required so the `devServer` can find the correct compilation + dependencies: [mainName], // will make webpack wait for the first + target: "node", + entry: { pages: resolve(source, "main.ts") }, + output: { + ...config.output, + // we are importing the module as a string, so we must bundle it as `commonjs` + chunkFormat: "commonjs", + library: { type: "commonjs" }, + }, + optimization: { + ...config.optimization, + minimize: false, + moduleIds: "named", + runtimeChunk: undefined, + }, + // we only care about compiling the `.ts` files in the `/src/pages` directory into `.html` files + plugins: [ + definePlugin, + new MubanPagePlugin({ template: resolve(publicDir, "index.html") }), + new CopyPlugin({ + patterns: [ + { + from: publicDir, + toType: "dir", + globOptions: { ignore: ["**/.*", resolve(publicDir, "index.html")] }, + }, + ], + }), + ], + }; +} + +function parseOptions(options) { + let { preview = false } = options; + + if (preview === "false") preview = false; + + return { preview }; +} + +export default function createConfig(config, options = {}) { + const isDev = config.mode + ? config.mode === "development" + : process.env.NODE_ENV === "development"; + + const { preview } = parseOptions(options); + + const mainName = "muban"; + const pagesName = "pages"; + + /** @type {import('webpack').Configuration[]} */ + return [ + // the "main" configuration for bundling the muban app + createMainConfig(config, { mainName, pagesName }), + // the "pages" configuration for bundling the static pages (also used to serve development pages) + (preview || isDev) && createPagesConfig(config, { mainName, pagesName }), + ].filter(Boolean); +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 37b390d..0000000 --- a/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -# Add paths to ignore like i.e. vendor files diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index f07793e..0000000 --- a/.prettierrc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 2, - "singleQuote": true, - "trailingComma": "all", - "proseWrap": "always", - "overrides": [ - { - "files": "*.json", - "options": { - "printWidth": 999999 - } - }, - { - "files": "*.scss", - "options": { - "singleQuote": false - } - } - ] -} diff --git a/.storybook/main.cjs b/.storybook/main.cjs new file mode 100644 index 0000000..229eaf5 --- /dev/null +++ b/.storybook/main.cjs @@ -0,0 +1,41 @@ +const CSS_TEST = /\.css$/; +const SCSS_TEST = /\.(scss|sass)$/; + +module.exports = { + core: { + builder: "webpack5", + }, + stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"], + staticDirs: [{ from: "../static", to: "static" }, "../src/pages/public", "static"], + async webpackFinal(config) { + const { getNestedConfigs, createConfig, createFindPlugin } = await import( + "@pota/webpack-skeleton/.pota/webpack/util.js" + ); + + const [mubanConfig] = await createConfig(await getNestedConfigs()); + + const findPlugin = createFindPlugin(mubanConfig); + const miniCssExtractLoader = findPlugin("MiniCssExtractPlugin").constructor.loader; + + return { + ...config, + resolve: { + ...config.resolve, + alias: { ...config.resolve.alias, ...mubanConfig.resolve.alias }, + }, + module: { + ...config.module, + rules: mubanConfig.module.rules.map((rule) => + // storybook needs the standard `style-loader` + [String(CSS_TEST), String(SCSS_TEST)].includes(String(rule.test)) + ? { + ...rule, + use: rule.use.map((use) => (use === miniCssExtractLoader ? "style-loader" : use)), + } + : rule + ), + }, + plugins: [...config.plugins, findPlugin("DefinePlugin")], + }; + }, +}; diff --git a/.storybook/main.ts b/.storybook/main.ts deleted file mode 100644 index 5899e55..0000000 --- a/.storybook/main.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { paths } from '../config/paths'; - -export default { - stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], - addons: [ - // "@storybook/addon-links", - // "@storybook/addon-essentials" - { - name: '@storybook/preset-scss', - options: { - sassLoaderOptions: { - additionalData: ` - @import "~seng-scss"; - @import "${paths.srcPath - .substring(paths.projectDir.length) - .replace(/\\/g, '/')}/styles/_global.scss"; - `, - }, - }, - }, - ], -}; diff --git a/.storybook/manager.js b/.storybook/manager.js new file mode 100644 index 0000000..9c9f263 --- /dev/null +++ b/.storybook/manager.js @@ -0,0 +1,6 @@ +import { addons } from '@storybook/addons'; +import mmTheme from './mm-theme'; + +addons.setConfig({ + theme: mmTheme, +}); diff --git a/.storybook/mm-theme.js b/.storybook/mm-theme.js new file mode 100644 index 0000000..dbc0521 --- /dev/null +++ b/.storybook/mm-theme.js @@ -0,0 +1,8 @@ +import { create } from '@storybook/theming'; + +export default create({ + base: 'dark', + brandTitle: 'Media.Monks', + brandUrl: 'https://media.monks.com/', + brandImage: './mm-theme-brand-logo.png', +}); diff --git a/.storybook/package.json b/.storybook/package.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.storybook/package.json @@ -0,0 +1 @@ +{} diff --git a/.storybook/preview.js b/.storybook/preview.js index 8408271..d391458 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,9 +1,9 @@ -import '../src/styles/main.scss'; - export const parameters = { actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/, + }, + }, }; - -// const sprite = document.createElement('img'); -// sprite.src = require('bootstrap-icons/bootstrap-icons.svg'); -// document.body.appendChild(sprite); diff --git a/.storybook/static/mm-theme-brand-logo.png b/.storybook/static/mm-theme-brand-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e38861fd2043592febc473011f0b1e31967d1599 GIT binary patch literal 10942 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 Dkd9O} literal 0 HcmV?d00001 diff --git a/.storybook/webpack.config.ts b/.storybook/webpack.config.ts deleted file mode 100644 index 353fcdb..0000000 --- a/.storybook/webpack.config.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { getClientEnvironment } from '../config/env'; -import { paths } from '../config/paths'; - -// webpack 4 version of the plugin -import webpack from '@storybook/core/node_modules/webpack'; - -// We will provide `paths.publicUrlOrPath` to our app -// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. -// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. -// Get environment variables to inject into our app. -const env = getClientEnvironment(paths.publicPath.slice(0, -1)); - -/** - * NOTE: Storybook still uses webpack 4, so might not be 1-on-1 compatible with - * the project webpack config, which uses webpack 5!! - */ -export default ({ config }) => { - // Add the src path so we can load the assets - config.resolve.modules = [paths.srcPath, ...config.resolve.modules]; - - config.plugins.push(new webpack.DefinePlugin(env.stringified)); - - // remove this rule that deals with SVGs and media files - config.module.rules = config.module.rules.filter( - (rule) => !(String(rule.test).includes('svg') || String(rule.test).includes('mp4')), - ); - // Add the rule back without the svg in it, jep, a bit hacky - config.module.rules.push({ - test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/, - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', - esModule: false, - }, - }); - - // Re-add the media rule but with esModule turned off, to be in sync with the other assets - config.module.rules.push({ - test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/, - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', - esModule: false, - }, - }); - - // Add a loader for the svg's - config.module.rules.push({ - test: /\.svg$/, - oneOf: [ - { - resourceQuery: /inline/, - use: [{ loader: 'raw-loader', options: { esModule: false } }, { loader: 'svgo-loader' }], - }, - { - use: [{ loader: 'url-loader' }, { loader: 'svgo-loader' }], - }, - ], - }); - - // Return the altered config - return config; -}; diff --git a/README.md b/README.md index 51c377f..c97c928 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,171 @@ -# πŸš€ Welcome to your new awesome project! +# webpack-skeleton [![downloads](https://badgen.now.sh/npm/dm/@pota/webpack-skeleton)](https://npmjs.org/package/@pota/webpack-skeleton) -## Scripts +
The skeleton with the foundational webpack configuration for bootstrapping new projects.
+
-### `yarn dev` +## Setup πŸš€ -Your goto script when running local development against local page templates with live and hot reloading when any of -your code changes. +You can create a new project using the `@pota/create` package. -- runs the code bundle with `WebpackDevServer`, hot-reloading your JS and CSS changes -- runs the server bundle to generate templates and serves them from express, live-reloading your HTML changes +```bash +npx @pota/create webpack my-webpack-app +``` -The dev server runs on `http://localhost:9000`. + -### `yarn build` +## Standards πŸ“’ -Creates a distribution build that outputs the JS and CSS files. Used in CI to deploy to your production websites. +This project follows the [MediaMonks Frontend Coding Standards](https://github.com/mediamonks/frontend-coding-standards) -Append `--watch` to the command to start this webpack in watch mode, enjoying super fast recompilations when your -local files changes. +## Features πŸ”‹ -When the `MUBAN_ANALYZE` environment variable is set, it will generate a bundle-analyzer output -report. +### Pota Commands -### `yarn build:preview` +#### **`build`** - builds the source using `webpack`. -Generates a full preview package including generated HTML files to upload to a preview server that's not connected to -any backend. - -### `yarn build:debug` +```bash +npm run build # or npx pota build +``` -Generates a quick debug build without any minification and other optimizations. Useful for quick integration tests -where you're not deploying to production yet, but want to see your changes on a (local) integration server as fast -as possible. +| Option | Type | Default | Description | +| ----------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| **`analyze`** | `{Boolean}` | `false` | When enabled, will open a bundle report after bundling. | +| **`cache`** | `{Boolean}` | `true` | Toggles webpack's [caching](https://webpack.js.org/configuration/cache/) behavior. | +| **`image-compression`** | `{Boolean}` | `true` | Toggles image compression. | +| **`mode`** | `{development\|production}` | `production` | Override webpack's [mode](https://webpack.js.org/configuration/mode). | +| **`output`** | `{String}` | `./build` | The build output directory. | +| **`source-map`** | `{false\|`[devtool](https://webpack.js.org/configuration/devtool/#devtool)`}` | `source-map` (production), `eval-source-map` (development) | Sets the style of source-map, for enhanced debugging. Disable or use faster options in you are having out of memory or other performance issues. | +| **`public-url`** | `{String}` | `/` | The location of static assets on your production server. | +| **`type-check`** | `{Boolean}` | `true` | When disabled, will ignore type related errors. | +| **`versioning`** | `{Boolean}` | `false` | When enabled, will copy assets in `./static` to a versioned directory in the output (e.g. `build/version/v2/static/...`). | -Append `--watch` to the command to start this webpack in watch mode, enjoying super fast recompilations when your -local files changes. Very useful for live local development against your CMS rendered pages. -### `yarn storybook` +
-Develop and test your components in storybook. +#### **`dev`** - starts the development service using `webpack-dev-server`. -### `yarn storybook:build` +```bash +npm run dev # or npx pota dev +``` -Make a deployable storybook build to showcase your components to others. +| Option | Type | Default | Description | +| ----------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | +| **`cache`** | `{Boolean}` | `true` | Toggle webpack's [caching](https://webpack.js.org/configuration/cache/) behavior. | +| **`https`** | `{Boolean}` | `false` | Run the development server with HTTPS. | +| **`image-compression`** | `{Boolean}` | `true` | Toggles image compression. | +| **`mode`** | `{development\|production}` | `production` | Override webpack's [mode](https://webpack.js.org/configuration/mode). | +| **`source-map`** | `{false\|`[devtool](https://webpack.js.org/configuration/devtool/#devtool)`}` | `source-map` (production), `eval-source-map` (development) | Sets the style of source-map, for enhanced debugging. Disable or use faster options in you are having out of memory or other performance issues. | +| **`type-check`** | `{Boolean}` | `true` | Toggles checking for type related errors. | -### `yarn preview` +
-Start a local server to see the result of `yarn build:preview` +*hidden TODOs* + -The dev server runs on `http://localhost:9001`. +
-### `yarn test` +### Scripts -> TODO +Non-Pota scripts defined in `"scripts"` of `package.json` and are runnable using `npm run {script}` -### `yarn test:e2e` -> TODO +| Script | Description | +| ------------------ | -------------------------------------------------------------------------- | +| **`check-types`** | Checks for type errors and unused variables/types in the source directory. | +| **`fix`** | Executes all `fix:*` commands in sequence. | +| **`fix:eslint`** | Executes `eslint:lint` and fixes fixable errors. | +| **`fix:prettier`** | Formats the source files using `prettier`. | +| **`lint`** | Executes all `lint:*` commands in sequence. | +| **`lint:eslint`** | Lints the source files using `eslint`. | +
+ +### JavaScript / TypeScript + +*hidden TODOs* + + +
+ +### CSS + +*hidden TODOs* + + +
+ +### Images + +*hidden TODOs* + + +
+ +### Misc. Assets + +*hidden TODOs* + + +
+ +### Linting & Formatting + +*hidden TODOs* + + +
+ +### Deployment + +*hidden TODOs* + + +
+ +### Git + +*hidden TODOs* + + +
+ +### Continuous Integration / Continuous Deployment + +#### Bitbucket + +`webpack-skeleton` comes with `bitbucket-pipelines.yml`, pre-configured to run `check-types`, `lint` and `test` scripts. + +*hidden TODOs* + \ No newline at end of file diff --git a/STATUS.MD b/STATUS.MD deleted file mode 100644 index 0a32238..0000000 --- a/STATUS.MD +++ /dev/null @@ -1,77 +0,0 @@ -# Muban Skeleton - -## Production build - -+ bundle JS and CSS -+ support lazy loading / code splitting -+ 3 build types - + dist mode (single build, output on disk) - + dev mode (run webpack dev server and serve files from memory, including HTMl generation) - / watch mode (output on disk, but watch change for a quick rebuild) -+ export generated HTML pages - -- exclude all templates - except the ones being actually used - -### Dev mode - -+ run express server to server HTML and js/css -+ output HTML from express, not from JS, to better simulate a built package -+ integrate webpack-dev-middleware and webpack-hot-middleware - -- implement live-reload for HTML reload -- implement proper hot-reloading for JS components - or maybe just reload the page? -- I noticed that the hot reloading for the new muban wouldn't work sometimes. E.g. when a - variable type error is fixed, it would continue to show the error. Only upon restarting the - server would it go away. (this is for server templates) - - -### Template rendering - -+ root template is always the "index.html" that includes the head and body with default info and app container -+ then there is a default layout template that can render blocks, with an optional header and footer -+ user can create their own layouts for other pages -+ each page can optionally specify to choose a custom layout to render -+ a layout or template decides what to render based on the provided data on the page - -### Pages - -+ a page is a TS file that exports a data object -+ it can also export a function that returns a data object, receiving "context" about the current page and the site - in general - - part of the context is the "sitemap", so automatic links to other pages can be generated - -- besides page data, allow for setting other info like metadata (title/description/og:tags) -- build up a "context" object for each page - -### Routing - -Both during dev mode, and when generating build pages, we need to know what Pages exist, and what to render. - -+ when no "index" file on disk is present, render auto-index instead -+ also support pages in folders - -+ files on disk should be pages - + urls should include .html -+ folder should redirect to index.html in the folder - -- make "router" available to templates? - -### Theming - -- support for themes/styles/variables -- make separate theme build -- other exceptions per theme (html? js?) -- pages per theme? theme variables? - - -#### Optional - -+ leave CSS bundled with JS files to reduce initial css load size - -/ API mocking - -- create auto-index page -- export only JS / CSS solo -- typed API ?? - -- check non-zero error codes on build diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 71ec882..0000000 --- a/babel.config.js +++ /dev/null @@ -1,172 +0,0 @@ -/* eslint-disable global-require,import/no-extraneous-dependencies */ - -const path = require('path'); - -const absoluteRuntimePath = path.dirname(require.resolve('@babel/runtime/package.json')); - -module.exports = function(api) { - api.cache(!api.env('production')); - - return { - presets: [ - [ - '@babel/preset-env', - { - // The starting point where the config search for browserslist will start, - // and ascend to the system root until found. - configPath: __dirname, - - // By default, @babel/preset-env (and Babel plugins in general) grouped ECMAScript syntax - // features into collections of closely related smaller features. These groups can be - // large and include a lot of edge cases, for example "function arguments" includes - // destructured, default and rest parameters. From this grouping information, - // Babel enables or disables each group based on the browser support target you specify - // to @babel/preset-env’s targets option. - // - // When this option is enabled, @babel/preset-env tries to compile the broken syntax to - // the closest non-broken modern syntax supported by your target browsers. - // Depending on your targets and on how many modern syntax you are using, - // this can lead to a significant size reduction in the compiled app. - // This option merges the features of @babel/preset-modules without having - // to use another preset. - bugfixes: true, - - // Setting this to false will preserve ES modules. Use this only if you intend to ship - // native ES Modules to browsers. If you are using a bundler with Babel, - // the default modules: "auto" is always preferred. - modules: 'auto', - - // This option configures how @babel/preset-env handles polyfills. - // When either the `usage` or `entry` options are used, @babel/preset-env will add direct - // references to core-js modules as bare imports (or requires). This means core-js will - // be resolved relative to the file itself and needs to be accessible. - // - // Since @babel/polyfill was deprecated in 7.4.0, we recommend directly adding core-js - // and setting the version via the corejs option. - useBuiltIns: 'entry', - - // This option only has an effect when used alongside `useBuiltIns: usage` or - // `useBuiltIns: entry`, and ensures @babel/preset-env injects the polyfills - // supported by your core-js version. - // By default, only polyfills for stable ECMAScript features are injected: - // if you want to polyfill proposals, you can directly import a proposal polyfill - // inside /src/polyfills.js: import "core-js/proposals/string-replace-all". - corejs: { version: "3.9" }, - - // An array of plugins to always exclude/remove. - // This option is useful for "blacklisting" a transform like - // @babel/plugin-transform-regenerator if you don't use generators and don't want to - // include regeneratorRuntime (when using useBuiltIns) or for using another plugin like - // fast-async instead of Babel's async-to-gen. - exclude: [ - // Exclude transforms that make all code slower - 'transform-typeof-symbol', - - // // we don't use generators or async/await by default - // 'transform-regenerator', - // - // // we don't use typed arrays by default - // 'es6.typed.*', - // - // // we don't use reflect by default - // 'es6.reflect.*', - // - // // we don't use symbols by default - // 'es6.symbol', - // - // // we don't use advanced regexps by default - // 'es6.regexp.*', - // - // // we don't use advanced math by default - // 'es6.math.acosh', - // 'es6.math.asinh', - // 'es6.math.atanh', - // 'es6.math.cbrt', - // 'es6.math.clz32', - // 'es6.math.cosh', - // 'es6.math.expm1', - // 'es6.math.fround', - // 'es6.math.hypot', - // 'es6.math.imul', - // 'es6.math.log1p', - // 'es6.math.log10', - // 'es6.math.log2', - // 'es6.math.sign', - // 'es6.math.sinh', - // 'es6.math.tanh', - // 'es6.math.trunc', - // - // // we don't use maps and sets by default - // 'es6.map', - // 'es6.set', - // 'es6.weak-map', - // 'es6.weak-set', - // - // // Funky unused HTML string methods - // 'es6.string.anchor', - // 'es6.string.big', - // 'es6.string.blink', - // 'es6.string.bold', - // 'es6.string.code-point-at', - // 'es6.string.fixed', - // 'es6.string.fontcolor', - // 'es6.string.fontsize', - // 'es6.string.from-code-point', - // 'es6.string.italics', - // 'es6.string.iterator', - // 'es6.string.link', - ], - }, - ], - [require('@babel/preset-typescript').default], - ], - plugins: [ - // class { handleClick = () => { } } - // Enable loose mode to use assignment instead of defineProperty - // See discussion in https://github.com/facebook/create-react-app/issues/4263 - [ - require('@babel/plugin-proposal-class-properties').default, - { - loose: true, - }, - ], - - // Adds Numeric Separators - require('@babel/plugin-proposal-numeric-separator').default, - - // Polyfills the runtime needed for async/await, generators, and friends - // https://babeljs.io/docs/en/babel-plugin-transform-runtime - [ - require('@babel/plugin-transform-runtime').default, - { - corejs: false, - helpers: true, - // By default, babel assumes babel/runtime version 7.0.0-beta.0, - // explicitly resolving to match the provided helper functions. - // https://github.com/babel/babel/issues/10261 - version: require('@babel/runtime/package.json').version, - regenerator: true, - // https://babeljs.io/docs/en/babel-plugin-transform-runtime#useesmodules - // We should turn this on once the lowest version of Node LTS - // supports ES Modules. - useESModules: true, // TODO disable for testing? - // Undocumented option that lets us encapsulate our runtime, ensuring - // the correct version is used - // https://github.com/babel/babel/blob/090c364a90fe73d36a30707fc612ce037bdbbb24/packages/babel-plugin-transform-runtime/src/index.js#L35-L42 - absoluteRuntime: absoluteRuntimePath, - }, - ], - 'lodash', - '@babel/plugin-syntax-dynamic-import', - '@babel/plugin-syntax-import-meta', - '@babel/plugin-proposal-json-strings', - ['@babel/plugin-proposal-decorators', { legacy: true }], - '@babel/plugin-proposal-function-sent', - '@babel/plugin-proposal-export-namespace-from', - '@babel/plugin-proposal-throw-expressions', - - // needed to register muban-components - '@babel/plugin-transform-react-display-name', - ], - }; -}; diff --git a/config/env.ts b/config/env.ts deleted file mode 100644 index 573d994..0000000 --- a/config/env.ts +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -import fs from 'fs'; -import path from 'path'; -import { paths } from './paths'; - -// Make sure that including paths.js after env.js will read .env variables. -delete require.cache[require.resolve('./paths')]; - -const NODE_ENV = process.env.NODE_ENV; -if (!NODE_ENV) { - throw new Error('The NODE_ENV environment variable is required but was not specified.'); -} - -// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use -const dotenvFiles = [ - `${paths.dotenv}.${NODE_ENV}.local`, - // Don't include `.env.local` for `test` environment - // since normally you expect tests to produce the same - // results for everyone - NODE_ENV !== 'test' && `${paths.dotenv}.local`, - `${paths.dotenv}.${NODE_ENV}`, - paths.dotenv, -].filter(Boolean) as Array; - -// Load environment variables from .env* files. Suppress warnings using silent -// if this file is missing. dotenv will never modify any environment variables -// that have already been set. Variable expansion is supported in .env files. -// https://github.com/motdotla/dotenv -// https://github.com/motdotla/dotenv-expand -dotenvFiles.forEach((dotenvFile) => { - if (fs.existsSync(dotenvFile)) { - require('dotenv-expand')( - require('dotenv').config({ - path: dotenvFile, - }), - ); - } -}); - -// We support resolving modules according to `NODE_PATH`. -// This lets you use absolute paths in imports inside large monorepos: -// https://github.com/facebook/create-react-app/issues/253. -// It works similar to `NODE_PATH` in Node itself: -// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders -// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored. -// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims. -// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421 -// We also resolve them to make sure all tools using them work consistently. -const appDirectory = fs.realpathSync(process.cwd()); -process.env.NODE_PATH = (process.env.NODE_PATH || '') - .split(path.delimiter) - .filter((folder) => folder && !path.isAbsolute(folder)) - .map((folder) => path.resolve(appDirectory, folder)) - .join(path.delimiter); - -// Grab NODE_ENV and MUBAN_* environment variables and prepare them to be -// injected into the application via DefinePlugin in webpack configuration. -const MUBAN = /^MUBAN_/i; - -export function getClientEnvironment(publicPath) { - const raw = Object.keys(process.env) - .filter((key) => MUBAN.test(key)) - .reduce( - (env, key) => { - env[key] = process.env[key]; - return env; - }, - { - // Useful for determining whether we’re running in production mode. - // Most importantly, it switches React into the correct mode. - NODE_ENV: process.env.NODE_ENV || 'development', - // Useful for resolving the correct path to static assets in `public`. - // For example, . - // This should only be used as an escape hatch. Normally you would put - // images into the `src` and `import` them in code to get their paths. - PUBLIC_PATH: publicPath, - // We support configuring the sockjs pathname during development. - // These settings let a developer run multiple simultaneous projects. - // They are used as the connection `hostname`, `pathname` and `port` - // in webpackHotDevClient. They are used as the `sockHost`, `sockPath` - // and `sockPort` options in webpack-dev-server. - WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, - WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, - WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, - }, - ); - // Stringify all values so we can feed into webpack DefinePlugin - const stringified = { - 'process.env': Object.keys(raw).reduce((env, key) => { - env[key] = JSON.stringify(raw[key]); - return env; - }, {}), - }; - - return { raw, stringified }; -} diff --git a/config/paths.ts b/config/paths.ts deleted file mode 100644 index 30396ae..0000000 --- a/config/paths.ts +++ /dev/null @@ -1,68 +0,0 @@ -import path from 'path'; -const argv = require('yargs').argv; - -const projectDir = path.resolve(__dirname, '../'); -const srcPath = path.resolve(projectDir, './src'); -const distPath = path.resolve(projectDir, './dist'); - -const resolveProject = (relativePath) => path.resolve(projectDir, relativePath); -const resolveSource = (relativePath) => path.resolve(srcPath, relativePath); -const resolveDist = (relativePath) => path.resolve(distPath, relativePath); - -const publicPath = getPublicPath('/'); -console.log('publicPath', publicPath); - -export const paths = { - dotenv: resolveProject('.env'), - packageJson: resolveProject('./package.json'), - nodeModules: resolveProject('./node_modules'), - projectDir, - srcPath, - distPath, - publicPath, - serverBundleEntry: path.resolve(srcPath, './server-bundle.ts'), - distSitePath: resolveDist('./site'), - distSiteStaticPath: resolveDist('./site/static'), - distMockNodePath: resolveDist('./node'), - mockPath: resolveProject('./mocks'), - webpackClientConfig: resolveProject('./config/webpack.config.ts'), - webpackServerConfig: resolveProject('./scripts/devserver/webpack.config.ts'), - serverBundleOutputDir: resolveProject('./scripts/devserver/output'), - serverBundleOutputEntry: resolveProject('./scripts/devserver/output/main.js'), - webpackMockConfig: resolveProject('./scripts/webpack.config.mock.js'), - devIndex: resolveProject('./scripts/devserver/index.html'), - distIndex: resolveProject('./scripts/devserver/index.html'), - webpackAssetPath: resolveSource('./assets'), // required through webpack - webpackAssetFonts: resolveSource('./assets/fonts'), - webpackAssetImages: resolveSource('./assets/images'), - publicAssetPath: resolveSource('./public'), // CopyWebpackPlugin - pagesPath: resolveSource('./pages'), // Only Dev and Preview - pagesAssetPath: resolveSource('./pages/static'), // Only Dev and Preview - tsConfig: resolveProject('./tsconfig.json'), -}; - -function getPublicPath(defaultPublicPath) { - let publicPath = defaultPublicPath; - - if (argv.publicPath) { - // TODO: currently not supported when using webpack-cli - // since that will validate any parameter - // Use process.env.PUBLIC_PATH instead - publicPath = argv.PUBLIC_PATH; - console.log('Using publicPath from "--publicPath"'); - } else if (process.env.PUBLIC_PATH) { - publicPath = process.env.PUBLIC_PATH; - console.log('Using publicPath from "process.env.PUBLIC_PATH"'); - } - - // force leading / if not relative with '.' - if (!publicPath.startsWith('/') && !publicPath.startsWith('.')) { - publicPath = `/${publicPath}`; - } - // force trailing / - if (!publicPath.endsWith('/')) { - publicPath = `${publicPath}/`; - } - - return publicPath; -} diff --git a/config/tsconfig.webpack.json b/config/tsconfig.webpack.json deleted file mode 100644 index 9c14c0c..0000000 --- a/config/tsconfig.webpack.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true - } -} \ No newline at end of file diff --git a/config/webpack.config.ts b/config/webpack.config.ts deleted file mode 100644 index d06d9d3..0000000 --- a/config/webpack.config.ts +++ /dev/null @@ -1,478 +0,0 @@ -import fs from 'fs'; -import path from 'path'; -import resolve from 'resolve'; -import webpack from 'webpack'; -import postcssNormalize from 'postcss-normalize'; -import PnpWebpackPlugin from 'pnp-webpack-plugin'; -import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; -import CopyWebpackPlugin from 'copy-webpack-plugin'; -import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; -import MiniCssExtractPlugin from 'mini-css-extract-plugin'; -import TerserPlugin from 'terser-webpack-plugin'; -import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; -import WatchMissingNodeModulesPlugin from 'react-dev-utils/WatchMissingNodeModulesPlugin'; -import ModuleScopePlugin from 'react-dev-utils/ModuleScopePlugin'; -import ModuleNotFoundPlugin from 'react-dev-utils/ModuleNotFoundPlugin'; -import ForkTsCheckerWebpackPlugin from 'react-dev-utils/ForkTsCheckerWebpackPlugin'; -import typescriptFormatter from 'react-dev-utils/typescriptFormatter'; -import { getClientEnvironment } from './env'; - -import { paths } from './paths'; - -const isPreview = process.env.MUBAN_PREVIEW === 'true'; -const analyze = process.env.MUBAN_ANALYZE === 'true'; - -// Check if TypeScript is setup -const useTypeScript = fs.existsSync(paths.tsConfig); - -// Source maps are resource heavy and can cause out of memory issue for large source files. -const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP === 'true'; - -const appPackageJson = require(paths.packageJson); - -// We will provide `paths.publicUrlOrPath` to our app -// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. -// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz. -// Get environment variables to inject into our app. -const env = getClientEnvironment(paths.publicPath.slice(0, -1)); - -module.exports = function () { - // console.log('webpack env', webpackEnv, argv); - const isEnvProduction = process.env.NODE_ENV === 'production'; - const isEnvDevelopment = process.env.NODE_ENV !== 'production'; - const mode = isEnvProduction ? 'production' : isEnvDevelopment && 'development'; - - console.log('mode', mode); - - return { - mode, - // Stop compilation early in production - bail: isEnvProduction, - devtool: isEnvProduction - ? shouldUseSourceMap - ? 'source-map' - : false - : isEnvDevelopment && 'cheap-module-source-map', - // TODO: create separate "preview" entry for the auto-index - entry: path.resolve(paths.srcPath, './index.ts'), - output: { - // The build folder. - path: path.resolve(paths.distSitePath, '.'), // change the sub folders in the respective loaders - // Add /* filename */ comments to generated require()s in the output. - pathinfo: isEnvDevelopment, - // There will be one main bundle, and one file per asynchronous chunk. - // In development, it does not produce real files. - // For consistent inclusions in server-generated pages, we don't add a [contenthash] - // in production either. - filename: 'static/js/[name].js', - // There are also additional JS chunk files if you use code splitting. - chunkFilename: `static/js/[name]${isEnvProduction ? '.[contenthash:8]' : ''}.chunk.js`, - // 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. - // TODO: add info about how to change this - publicPath: paths.publicPath, - // Point sourcemap entries to original disk location (format as URL on Windows) - devtoolModuleFilenameTemplate: isEnvProduction - ? (info) => path.relative(paths.srcPath, info.absoluteResourcePath).replace(/\\/g, '/') - : isEnvDevelopment && - ((info) => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), - // this defaults to 'window', but by setting it to 'this' then - // module chunks which are built will work in web workers as well. - globalObject: 'this', - }, - - resolve: { - extensions: ['.ts', '.js'], - plugins: [ - // Adds support for installing with Plug'n'Play, leading to faster installs and adding - // guards against forgotten dependencies and such. - // PnpWebpackPlugin, - // Prevents users from importing files from outside of src/ (or node_modules/). - // This often causes confusion because we only process files within src/ with babel. - // To fix this, we prevent you from importing files out of src/ -- if you'd like to, - // please link the files into your node_modules/ and let module-resolution kick in. - // Make sure your source files are compiled, as they will not be processed in any way. - // TODO: doesn't work with mini-css-extract-plugin - // new ModuleScopePlugin(paths.srcPath, [ - // paths.packageJson, - // ]), - ], - modules: [paths.srcPath, 'node_modules'], - }, - resolveLoader: { - plugins: [ - // Also related to Plug'n'Play, but this time it tells webpack to load its loaders - // from the current package. - // PnpWebpackPlugin.moduleLoader(module), - ], - }, - - module: { - rules: [ - { - // "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$/, - enforce: 'pre', - use: [require.resolve('source-map-loader')], - }, - // Process application JS with Babel. - // The preset includes JSX, Flow, TypeScript, and some ESnext features. - { - test: /\.(js|mjs|ts)$/, - include: paths.srcPath, - loader: require.resolve('babel-loader'), - options: { - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/babel-loader/ - // directory for faster rebuilds. - cacheDirectory: true, - // See #6846 for context on why cacheCompression is disabled - cacheCompression: false, - compact: isEnvProduction, - }, - }, - // { - // test: /\.(ts|tsx)$/, - // loader: require.resolve('ts-loader'), - // include: [paths.srcPath], - // exclude: [/node_modules/], - // }, - // "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