Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Config file instead of Environment Variables #2227

Merged
merged 28 commits into from
Dec 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2959334
Add cosmiconfig
AlbertoBrusa Dec 6, 2022
e1571dd
Allow use esbuild to be configured by a modular configuration file
AlbertoBrusa Dec 7, 2022
dac6289
Update comments
AlbertoBrusa Dec 7, 2022
7fb5370
Update config logic
AlbertoBrusa Dec 8, 2022
33742bf
Fix config
AlbertoBrusa Dec 9, 2022
cde234d
Change the default CDN to esm.sh
AlbertoBrusa Dec 9, 2022
dc77942
Update test snapshots for change to esm.sh
AlbertoBrusa Dec 9, 2022
cec53a1
More configurables
AlbertoBrusa Dec 12, 2022
f854b5e
https config
AlbertoBrusa Dec 12, 2022
249390f
Let JS files in react-scripts use config.ts using ts-node/register
AlbertoBrusa Dec 13, 2022
7e08f6a
Fix ts-node register
AlbertoBrusa Dec 13, 2022
b9b4f5b
More require ts-node register
AlbertoBrusa Dec 13, 2022
675b10f
Remove HOST and HTTPS config
AlbertoBrusa Dec 14, 2022
73fee89
Configurable PUBLIC_URL & GENERATE_SOURCEMAP
AlbertoBrusa Dec 15, 2022
b08bd37
Undo changes for PUBLIC_URL & GENERATE_SOURCEMAP config
AlbertoBrusa Dec 15, 2022
5054f28
2nd attempt re-implementing config for generate sourcemap and public url
AlbertoBrusa Dec 15, 2022
755a13f
Add changeset
AlbertoBrusa Dec 15, 2022
1a447a3
Documentation
AlbertoBrusa Dec 15, 2022
ee938f7
Update changelog
AlbertoBrusa Dec 15, 2022
7eead44
Update documentation
AlbertoBrusa Dec 15, 2022
5a94077
Update docs/releases/4.0.x.md
AlbertoBrusa Dec 16, 2022
142b7ef
Update documentation
AlbertoBrusa Dec 16, 2022
c085182
Merge branch 'config' of https://github.com/AlbertoBrusa/modular into…
AlbertoBrusa Dec 16, 2022
c8ef95c
Improved config function
AlbertoBrusa Dec 16, 2022
6175809
Update config function
AlbertoBrusa Dec 16, 2022
f73878e
Refactor config function
AlbertoBrusa Dec 16, 2022
7448a3b
Removed unnecessary type annotations
AlbertoBrusa Dec 16, 2022
f0e2e93
More cleaning up of Config()
AlbertoBrusa Dec 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/cyan-flowers-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'modular-scripts': major
---

Changed default CDN from Skypack to esm.sh as skypack is no longer actively
maintained. Add support for configuring modular through a configuration file.
3 changes: 3 additions & 0 deletions __fixtures__/test-config/.modular.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
useModularEsbuild: true,
};
97 changes: 95 additions & 2 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,101 @@ nav_order: 10

# Configuration

Modular has minimal configuration because of its philosophy. However there is a
set of minimum configuration required.
Because of its philosophy, Modular has a restricted set of configurable
behaviours. Additionally it requires some minimal configuration within the
`package.json`s in the repository, all handled by Modular itself.

## Configuration File

We allow a number of Modular behaviours to be configured via a dedicated Modular
config file, `.modular.js`, located at the root of the repository.

We support the following file names/formats:

- `modular` property within your `package.json`
- `.modular.js`
- `.modularrc`
- `.modularrc.json`
- `.modularrc.yaml`
- `.modularrc.yml`
- `.modularrc.js`
- `.modularrc.cjs`
- `modular.config.js`
- `modular.config.cjs`

Example `.modular.js` file contents with all configurable attributes and their
default values:

```js
module.exports = {
useModularEsbuild: false,
externalCdnTemplate: 'https://esm.sh/[name]@[version]',
externalBlockList: [],
externalAllowList: ['**'],
publicUrl: '',
generateSourceMap: true,
};
```

### **useModularEsbuild**

**Type**: `boolean`

**Default**: `false` - Uses [Webpack](https://webpack.js.org/)

Use esbuild instead of default Webpack. Only affects Views and ESM Views.

### **externalCdnTemplate**

**Type**: `string`

**Default**: `https://esm.sh/[name]@[version]` - [esm.sh](https://esm.sh/)

Template to resolve the URL used to fetch packages from a CDN. Defaults to
esm.sh. Only applies to ESM Views.

### **externalBlockList**

**Type**: `string[]`

**Default**: `[]` - No packages

Packages that should be bundled and not fetched from a CDN. We recommend
allowing all packages to be handled by the CDN, except for particular cases
where they would not work correctly. See
[known-limitations](./esm-views/known-limitations.md). Defaults to none. Only
applies to ESM Views.

### **externalAllowList**

**Type**: `string[]`

**Default**: `[**]` - All packages

Packages that should be fetched from a CDN. We recommend allowing all packages
to be handled by the CDN, except for particular cases where they would not work
correctly. See [known-limitations](./esm-views/known-limitations.md). Defaults
to all packages. Only applies to ESM Views.

### **publicUrl**

**Type**: `string`

**Default**: `''` - No Public URL

Same as Create React App PUBLIC_URL. Instead of assuming the application is
hosted in the web server's root or subpath specified by homepage in
package.json, assets will be referenced to the URL provided.

### **generateSourceMap**

**Type**: `boolean`

**Default**: `true`

Should build process generate a source map - can be disabled for performance
reasons. Source maps are resource heavy and can cause out of memory issue for
large source files.

## `package.json#modular`

Expand Down
20 changes: 11 additions & 9 deletions docs/esm-views/customize-bundle-strategy.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ title: Customize bundling strategy
# Customize bundling / rewriting strategy

By default, all external dependencies are rewritten to a CDN URL and none is
bundled. This logic can be controlled using two environment variables:

1. `EXTERNAL_ALLOW_LIST` is a comma-separated string that specifies which
dependencies are allowed to be rewritten to the CDN; if not specified, its
default value is `**` ( -> all dependencies are rewritten)
2. `EXTERNAL_BLOCK_LIST` is a comma-separated string that specifies which
dependencies are **not** allowed to be rewritten to the CDN; if not specified
its default value is empty ( -> no dependency excluded, i.e. all dependencies
are rewritten)
bundled. This logic can be controlled using two environment variables or by
using a [modular configuration file](../configuration.md).:

1. [`EXTERNAL_ALLOW_LIST`](../configuration.md#externalallowlist) is a
comma-separated string that specifies which dependencies are allowed to be
rewritten to the CDN; if not specified, its default value is `**` ( -> all
dependencies are rewritten)
2. [`EXTERNAL_BLOCK_LIST`](../configuration.md#externalblocklist) is a
comma-separated string that specifies which dependencies are **not** allowed
to be rewritten to the CDN; if not specified its default value is empty ( ->
no dependency excluded, i.e. all dependencies are rewritten)

The allow / block lists are parsed and processed according to this logic:

Expand Down
3 changes: 2 additions & 1 deletion docs/esm-views/esm-cdn.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ evaluated only once, it plays well with stateful libraries.
# Customise the ESM CDN

You can specify a CDN template to rewrite dependencies using the environment
variable `EXTERNAL_CDN_TEMPLATE`.
variable [`EXTERNAL_CDN_TEMPLATE`](../configuration.md#externalcdntemplate), or
by using a [modular configuration file](../configuration.md).

For example:

Expand Down
8 changes: 8 additions & 0 deletions docs/releases/4.0.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ title: 4.0.x

- Node 18 Support
- Updated Jest to [^29.3.1](https://github.com/facebook/jest/releases)
- Support for a dedicated [Modular configuration file](../configuration.md)

## Breaking Changes

Expand Down Expand Up @@ -66,6 +67,13 @@ manually complete the tasks previously covered by these commands.
- Dropped support for minor versions of Node 14.17 and Node 16 version 16.9 and
below
- Now support Node ^14.18.0, >=16.10.0, and >=18.0.0
- Dropped `USE_MODULAR_WEBPACK` environment variable, as Webpack is used by
default. Use `USE_MODULAR_ESBUILD` env variable or `useModularEsbuild` in a
[modular configuration file](../configuration.md) to use esbuild
- Changed default Content Delivery Network for ESM Views to esm.sh instead of
Skypack, as it is no longer actively maintained. The CDN can still be
configured through the `EXTERNAL_CDN_TEMPLATE` environment variable or through
a [modular configuration file](../configuration.md).

# Merged Changes

Expand Down
2 changes: 2 additions & 0 deletions packages/modular-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"@rollup/plugin-node-resolve": "13.3.0",
"@svgr/core": "6.2.1",
"@svgr/webpack": "6.2.1",
"@types/lodash": "^4.14.191",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure in the slightest why that popped up now but it was complaining for missing typings for lodash

"@types/micromatch": "4.0.2",
"@types/npmcli__arborist": "^5.6.0",
"@types/yarnpkg__lockfile": "^1.1.5",
Expand All @@ -49,6 +50,7 @@
"chalk": "4.1.2",
"change-case": "4.1.2",
"commander": "9.4.0",
"cosmiconfig": "^8.0.0",
"cross-spawn": "7.0.3",
"css-loader": "6.7.1",
"css-minimizer-webpack-plugin": "3.4.1",
Expand Down
4 changes: 3 additions & 1 deletion packages/modular-scripts/react-scripts/config/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ const resolveModular = (relativePath) =>
const publicUrlOrPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.PUBLIC_URL,
process.env.INTERNAL_PUBLIC_URL === ''
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

letting getConfig return undefined would have been messy, but treating '' (empty string) as configuration not set might not be ideal either, open to suggestions

? undefined
: process.env.INTERNAL_PUBLIC_URL,
);

const buildPath = path.join(modularRoot, 'dist', modularPackageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const useReactCreateRoot = getEnvironmentVariable(
const styleImports = getEnvironmentVariable('MODULAR_STYLE_IMPORT_MAPS', []);

// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
const shouldUseSourceMap = process.env.INTERNAL_GENERATE_SOURCEMAP !== 'false';

const imageInlineSizeLimit = parseInt(
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000',
Expand Down
2 changes: 0 additions & 2 deletions packages/modular-scripts/react-scripts/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@ const isCI = require('is-ci');
const paths = require('../config/paths');
const configFactory = require('../config/webpack.config');
const createDevServerConfig = require('../config/webpackDevServer.config');

const isInteractive = process.stdout.isTTY;

// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';

if (process.env.HOST) {
log(
chalk.cyan(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`modular-scripts WHEN building a esm-view THEN matches the entrypoint snapshot 1`] = `
"import * as t from "https://cdn.skypack.dev/react@17.0.2";
"import * as t from "https://esm.sh/react@17.0.2";
function e() {
return t.createElement(
"div",
Expand Down
51 changes: 51 additions & 0 deletions packages/modular-scripts/src/__tests__/utils/config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import execa from 'execa';
import { copyFileSync } from 'fs';
import path from 'path';
import { createModularTestContext } from '../../test/utils';
import getModularRoot from '../../utils/getModularRoot';

const modularRoot = getModularRoot();
const configFixtures = path.join(modularRoot, '__fixtures__', 'test-config');

/**
* Run modular with provided arguments in specified directory
*/
function modular(
args: string,
cwd: string,
opts: Record<string, unknown> = {},
) {
return execa('yarnpkg', ['modular', ...args.split(' ')], {
cwd,
cleanup: true,
...opts,
});
}

// Temporary test context paths set by createTempModularRepoWithTemplate()
let tempModularRepo: string;

describe('A simple modular repo with a .modular.js config file', () => {
beforeEach(async () => {
tempModularRepo = createModularTestContext();
await modular('add test-app --unstable-type app', tempModularRepo);
copyFileSync(
path.join(configFixtures, '.modular.js'),
path.join(tempModularRepo, '.modular.js'),
);
});
it('builds using esbuild as specified in config file', async () => {
const result = await modular(`build test-app --verbose`, tempModularRepo);
expect(result.stdout).toContain('Building with esbuild');
expect(result.exitCode).toBe(0);
});
it('builds using webpack if the environment variable is provided as it overrides the config', async () => {
const result = await modular(`build test-app --verbose`, tempModularRepo, {
env: {
USE_MODULAR_ESBUILD: 'false',
},
});
expect(result.stdout).toContain('Building with Webpack');
expect(result.exitCode).toBe(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import getRelativeLocation from '../../utils/getRelativeLocation';
import createEsbuildBrowserslistTarget from '../../utils/createEsbuildBrowserslistTarget';

import type { ModularPackageJson } from '@modular-scripts/modular-types';
import { getConfig } from '../../utils/config';

const outputDirectory = 'dist';
const extensions = ['.ts', '.tsx', '.js', '.jsx'];
Expand Down Expand Up @@ -107,7 +108,7 @@ export async function makeBundle(

const outputOptions: rollup.OutputOptions = {
freeze: false,
sourcemap: true, // TODO: read this off env
sourcemap: getConfig('generateSourceMap'),
sourcemapPathTransform(relativeSourcePath: string, sourceMapPath: string) {
// make source map input files relative to the `${packagePath}/dist-${format}` within
// the package directory
Expand Down
19 changes: 6 additions & 13 deletions packages/modular-scripts/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,13 @@ import {
} from './esbuildFileSizeReporter';
import { getDependencyInfo } from '../utils/getDependencyInfo';
import { isReactNewApi } from '../utils/isReactNewApi';
import { getConfig } from '../utils/config';

async function buildStandalone(
target: string,
type: Extract<ModularType, 'app' | 'esm-view'>,
) {
// True if there's no preference set - or the preference is for webpack.
const useWebpack =
!process.env.USE_MODULAR_WEBPACK ||
process.env.USE_MODULAR_WEBPACK === 'true';

// True if the preferene IS set and the preference is esbuid.
const useEsbuild =
process.env.USE_MODULAR_ESBUILD &&
process.env.USE_MODULAR_ESBUILD === 'true';

// If you want to use webpack then we'll always use webpack. But if you've indicated
// you want esbuild - then we'll switch you to the new fancy world.
const isEsbuild = !useWebpack || useEsbuild;
const isEsbuild = getConfig('useModularEsbuild');

// Setup Paths
const modularRoot = getModularRoot();
Expand Down Expand Up @@ -132,6 +121,7 @@ async function buildStandalone(
let cssEntryPoint: string | undefined;

if (isEsbuild) {
logger.debug('Building with esbuild');
const { default: buildEsbuildApp } = await import(
'../esbuild-scripts/build'
);
Expand All @@ -140,6 +130,7 @@ async function buildStandalone(
cssEntryPoint = getEntryPoint(paths, result, '.css');
assets = createEsbuildAssets(paths, result);
} else {
logger.debug('Building with Webpack');
// create-react-app doesn't support plain module outputs yet,
// so --preserve-modules has no effect here

Expand All @@ -160,6 +151,8 @@ async function buildStandalone(
MODULAR_IS_APP: JSON.stringify(isApp),
MODULAR_IMPORT_MAP: JSON.stringify(Object.fromEntries(importMap || [])),
MODULAR_USE_REACT_CREATE_ROOT: JSON.stringify(useReactCreateRoot),
INTERNAL_PUBLIC_URL: getConfig('publicUrl'),
INTERNAL_GENERATE_SOURCEMAP: String(getConfig('generateSourceMap')),
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as logger from '../../utils/logger';
import moduleScopePlugin from '../plugins/moduleScopePlugin';
import svgrPlugin from '../plugins/svgr';
import workerFactoryPlugin from '../plugins/workerFactoryPlugin';
import { getConfig } from '../../utils/config';

export default function createEsbuildConfig(
paths: Paths,
Expand Down Expand Up @@ -46,7 +47,7 @@ export default function createEsbuildConfig(
resolveExtensions: paths.moduleFileExtensions.map(
(extension) => `.${extension}`,
),
sourcemap: true,
sourcemap: getConfig('generateSourceMap'),
loader: {
// loaders for images which are supported as files
'.avif': 'file',
Expand Down
Loading