Skip to content

Commit

Permalink
Add buildOptions.metaDir option (#456)
Browse files Browse the repository at this point in the history
  • Loading branch information
drwpow committed Jun 10, 2020
1 parent 2f361ce commit b76ce6e
Show file tree
Hide file tree
Showing 17 changed files with 494 additions and 32 deletions.
6 changes: 6 additions & 0 deletions docs/05-configuration.md
Expand Up @@ -50,6 +50,7 @@ $ snowpack dev --no-bundle
"scripts": { /* ... */ },
"installOptions": { /* ... */ },
"devOptions": { /* ... */ },
"buildOptions": { /* ... */ },
"proxy": { /* ... */ },
}
```
Expand Down Expand Up @@ -120,6 +121,11 @@ $ snowpack dev --no-bundle
- **`hmr`** | `boolean` | Default: `true`
- Toggles whether or not Snowpack dev server should have HMR enabled.

#### Build Options

- **`metaDir`** | `string` | Default: `__snowpack__`
- By default, Snowpack outputs Snowpack-related metadata such as [HMR](#hot-module-replacement) and [ENV](#environment-variables) info to a folder called `__snowpack__`. You can rename that folder with this option (e.g.: `metaDir: 'static/snowpack'`).

#### Proxy Options

```js
Expand Down
4 changes: 3 additions & 1 deletion package.json
Expand Up @@ -16,7 +16,9 @@
"publish": "pika publish",
"version": "npm run build",
"format": "prettier --write \"src/**/*.ts\"",
"test": "jest test/integration/runner.js --test-timeout=15000 --testMatch \"**/test/**/*.[jt]s?(x)\" -i",
"test": "npm run test:integration && npm run test:build",
"test:build": "jest test/build",
"test:integration": "jest test/integration/runner.js --test-timeout=15000 --testMatch \"**/test/**/*.[jt]s?(x)\" -i",
"docs:build": "cat docs/* > www/index.md && npx @11ty/eleventy --config www/.eleventy.js",
"docs:watch": "cat docs/* > www/index.md && npx @11ty/eleventy --config www/.eleventy.js --serve",
"docs:deploy": "npm run docs:build && cp now.json www/dist && cd www/dist && now"
Expand Down
72 changes: 57 additions & 15 deletions src/commands/build-util.ts
Expand Up @@ -4,7 +4,12 @@ import execa from 'execa';
import path from 'path';
import {statSync} from 'fs';
import npmRunPath from 'npm-run-path';
import {BuildScript, SnowpackPluginBuildArgs, SnowpackPluginBuildResult} from '../config';
import {
SnowpackConfig,
BuildScript,
SnowpackPluginBuildArgs,
SnowpackPluginBuildResult,
} from '../config';

const IS_PREACT = /from\s+['"]preact['"]/;
export function checkIsPreact(filePath: string, contents: string) {
Expand All @@ -22,28 +27,45 @@ export function isDirectoryImport(fileLoc: string, spec: string): boolean {
return false;
}

export function wrapImportMeta(code: string, {hmr, env}: {hmr: boolean; env: boolean}) {
export function wrapImportMeta({
code,
hmr,
env,
config: {buildOptions},
}: {
code: string;
hmr: boolean;
env: boolean;
config: SnowpackConfig;
}) {
if (!code.includes('import.meta')) {
return code;
}
return (
(hmr
? `import * as __SNOWPACK_HMR__ from '/__snowpack__/hmr.js';\nimport.meta.hot = __SNOWPACK_HMR__.createHotContext(import.meta.url);\n`
? `import * as __SNOWPACK_HMR__ from '/${buildOptions.metaDir}/hmr.js';\nimport.meta.hot = __SNOWPACK_HMR__.createHotContext(import.meta.url);\n`
: ``) +
(env
? `import __SNOWPACK_ENV__ from '/__snowpack__/env.js';\nimport.meta.env = __SNOWPACK_ENV__;\n`
? `import __SNOWPACK_ENV__ from '/${buildOptions.metaDir}/env.js';\nimport.meta.env = __SNOWPACK_ENV__;\n`
: ``) +
'\n' +
code
);
}

export async function wrapCssModuleResponse(
url: string,
code: string,
ext: string,
export async function wrapCssModuleResponse({
url,
code,
ext,
hasHmr = false,
) {
config: {buildOptions},
}: {
url: string;
code: string;
ext: string;
hasHmr?: boolean;
config: SnowpackConfig;
}) {
let core = new Core();
const {injectableSource, exportTokens} = await core.load(code, url, () => {
throw new Error('Imports in CSS Modules are not yet supported.');
Expand All @@ -62,7 +84,7 @@ document.head.appendChild(styleEl);
${
hasHmr
? `
import * as __SNOWPACK_HMR_API__ from '/__snowpack__/hmr.js';
import * as __SNOWPACK_HMR_API__ from '/${buildOptions.metaDir}/hmr.js';
import.meta.hot = __SNOWPACK_HMR_API__.createHotContext(import.meta.url);
import.meta.hot.accept(({module}) => {
code = module.code;
Expand All @@ -76,22 +98,42 @@ import.meta.hot.dispose(() => {
}`;
}

export function wrapHtmlResponse(code: string, hasHmr = false) {
export function wrapHtmlResponse({
code,
hasHmr = false,
buildOptions,
}: {
code: string;
hasHmr?: boolean;
buildOptions: SnowpackConfig['buildOptions'];
}) {
if (hasHmr) {
code += `<script type="module" src="/__snowpack__/hmr.js"></script>`;
code += `<script type="module" src="/${buildOptions.metaDir}/hmr.js"></script>`;
}
return code;
}

export function wrapEsmProxyResponse(url: string, code: string, ext: string, hasHmr = false) {
export function wrapEsmProxyResponse({
url,
code,
ext,
hasHmr = false,
config: {buildOptions},
}: {
url: string;
code: string;
ext: string;
hasHmr?: boolean;
config: SnowpackConfig;
}) {
if (ext === '.json') {
return `
let json = ${JSON.stringify(JSON.parse(code))};
export default json;
${
hasHmr
? `
import * as __SNOWPACK_HMR_API__ from '/__snowpack__/hmr.js';
import * as __SNOWPACK_HMR_API__ from '/${buildOptions.metaDir}/hmr.js';
import.meta.hot = __SNOWPACK_HMR_API__.createHotContext(import.meta.url);
import.meta.hot.accept(({module}) => {
json = module.default;
Expand All @@ -114,7 +156,7 @@ document.head.appendChild(styleEl);
${
hasHmr
? `
import * as __SNOWPACK_HMR_API__ from '/__snowpack__/hmr.js';
import * as __SNOWPACK_HMR_API__ from '/${buildOptions.metaDir}/hmr.js';
import.meta.hot = __SNOWPACK_HMR_API__.createHotContext(import.meta.url);
import.meta.hot.accept();
import.meta.hot.dispose(() => {
Expand Down
18 changes: 14 additions & 4 deletions src/commands/build.ts
Expand Up @@ -78,7 +78,7 @@ export async function command(commandOptions: CommandOptions) {
}

const buildDirectoryLoc = isBundled ? path.join(cwd, `.build`) : config.devOptions.out;
const internalFilesBuildLoc = path.join(buildDirectoryLoc, '__snowpack__');
const internalFilesBuildLoc = path.join(buildDirectoryLoc, config.buildOptions.metaDir);
const finalDirectoryLoc = config.devOptions.out;

if (config.scripts.length <= 1) {
Expand Down Expand Up @@ -331,7 +331,7 @@ export async function command(commandOptions: CommandOptions) {
});
return `/web_modules/${spec}.js`;
});
code = wrapImportMeta(code, {env: true, hmr: false});
code = wrapImportMeta({code, env: true, hmr: false, config});
}
await fs.mkdir(path.dirname(outPath), {recursive: true});
await fs.writeFile(outPath, code);
Expand All @@ -347,15 +347,25 @@ export async function command(commandOptions: CommandOptions) {
const proxiedCode = await fs.readFile(proxiedFileLoc, {encoding: 'utf8'});
const proxiedExt = path.extname(proxiedFileLoc);
const proxiedUrl = proxiedFileLoc.substr(buildDirectoryLoc.length);
const proxyCode = await wrapCssModuleResponse(proxiedUrl, proxiedCode, proxiedExt);
const proxyCode = await wrapCssModuleResponse({
url: proxiedUrl,
code: proxiedCode,
ext: proxiedExt,
config,
});
const proxyFileLoc = proxiedFileLoc.replace('.module.css', '.css.module.js');
await fs.writeFile(proxyFileLoc, proxyCode, {encoding: 'utf8'});
}
for (const proxiedFileLoc of allProxiedFiles) {
const proxiedCode = await fs.readFile(proxiedFileLoc, {encoding: 'utf8'});
const proxiedExt = path.extname(proxiedFileLoc);
const proxiedUrl = proxiedFileLoc.substr(buildDirectoryLoc.length);
const proxyCode = wrapEsmProxyResponse(proxiedUrl, proxiedCode, proxiedExt);
const proxyCode = wrapEsmProxyResponse({
url: proxiedUrl,
code: proxiedCode,
ext: proxiedExt,
config,
});
const proxyFileLoc = proxiedFileLoc + '.proxy.js';
await fs.writeFile(proxyFileLoc, proxyCode, {encoding: 'utf8'});
}
Expand Down
37 changes: 25 additions & 12 deletions src/commands/dev.ts
Expand Up @@ -480,11 +480,11 @@ export async function command(commandOptions: CommandOptions) {
}
});

if (reqPath === '/__snowpack__/hmr.js') {
if (reqPath === `/${config.buildOptions.metaDir}/hmr.js`) {
sendFile(req, res, HMR_DEV_CODE, '.js');
return;
}
if (reqPath === '/__snowpack__/env.js') {
if (reqPath === `/${config.buildOptions.metaDir}/env.js`) {
sendFile(req, res, generateEnvModule('development'), '.js');
return;
}
Expand Down Expand Up @@ -586,12 +586,13 @@ export async function command(commandOptions: CommandOptions) {
if (virtualResourceResponse) {
if (isProxyModule) {
responseFileExt = '.js';
virtualResourceResponse = wrapEsmProxyResponse(
reqPath,
virtualResourceResponse,
requestedFileExt,
true,
);
virtualResourceResponse = wrapEsmProxyResponse({
url: reqPath,
code: virtualResourceResponse,
ext: requestedFileExt,
hasHmr: true,
config,
});
}
sendFile(req, res, virtualResourceResponse, responseFileExt);
return;
Expand All @@ -615,15 +616,27 @@ export async function command(commandOptions: CommandOptions) {

async function wrapResponse(code: string, cssResource: string | undefined) {
if (isRoute) {
code = wrapHtmlResponse(code, isHmr);
code = wrapHtmlResponse({code: code, hasHmr: isHmr, buildOptions: config.buildOptions});
} else if (isProxyModule) {
responseFileExt = '.js';
code = wrapEsmProxyResponse(reqPath, code, requestedFileExt, isHmr);
code = wrapEsmProxyResponse({
url: reqPath,
code,
ext: requestedFileExt,
hasHmr: isHmr,
config,
});
} else if (isCssModule) {
responseFileExt = '.js';
code = await wrapCssModuleResponse(reqPath, code, requestedFileExt, isHmr);
code = await wrapCssModuleResponse({
url: reqPath,
code,
ext: requestedFileExt,
hasHmr: isHmr,
config,
});
} else if (responseFileExt === '.js') {
code = wrapImportMeta(code, {env: true, hmr: isHmr});
code = wrapImportMeta({code, env: true, hmr: isHmr, config});
}
if (responseFileExt === '.js' && cssResource) {
code = `import './${path.basename(reqPath).replace(/.js$/, '.css.proxy.js')}';\n` + code;
Expand Down
17 changes: 17 additions & 0 deletions src/config.ts
Expand Up @@ -114,6 +114,9 @@ export interface SnowpackConfig {
dedupe?: string[];
};
};
buildOptions: {
metaDir: string;
};
proxy: Proxy[];
}

Expand Down Expand Up @@ -152,6 +155,9 @@ const DEFAULT_CONFIG: Partial<SnowpackConfig> = {
hmr: true,
bundle: undefined,
},
buildOptions: {
metaDir: '__snowpack__',
},
};

const configSchema = {
Expand Down Expand Up @@ -215,6 +221,12 @@ const configSchema = {
},
},
},
buildOptions: {
type: ['object'],
properties: {
metaDir: {type: 'string'},
},
},
proxy: {
type: 'object',
},
Expand All @@ -231,6 +243,7 @@ function expandCliFlags(flags: CLIFlags): DeepPartial<SnowpackConfig> {
const result = {
installOptions: {} as any,
devOptions: {} as any,
buildOptions: {} as any,
};
const {help, version, reload, config, ...relevantFlags} = flags;
for (const [flag, val] of Object.entries(relevantFlags)) {
Expand Down Expand Up @@ -450,6 +463,10 @@ function normalizeConfig(config: SnowpackConfig): SnowpackConfig {
config.proxy = {} as any;
}
const allPlugins = {};
// remove leading/trailing slashes
config.buildOptions.metaDir = config.buildOptions.metaDir
.replace(/^(\/|\\)/g, '') // replace leading slash
.replace(/(\/|\\)$/g, ''); // replace trailing slash
config.plugins = (config.plugins as any).map((plugin: string | [string, any]) => {
const configPluginPath = Array.isArray(plugin) ? plugin[0] : plugin;
const configPluginOptions = (Array.isArray(plugin) && plugin[1]) || {};
Expand Down
1 change: 1 addition & 0 deletions test/build/metadata-dir/.gitignore
@@ -0,0 +1 @@
build
9 changes: 9 additions & 0 deletions test/build/metadata-dir/index.test.js
@@ -0,0 +1,9 @@
const fs = require('fs');
const path = require('path');
const execa = require('execa');

it('buildOptions.metaDir', () => {
execa('node', ['npm', 'run', 'TEST']);
// expect dir in package.json to exist
expect(fs.existsSync(path.resolve(__dirname, 'build', 'static', 'snowpack')));
});
21 changes: 21 additions & 0 deletions test/build/metadata-dir/node_modules/shallow-equal/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b76ce6e

Please sign in to comment.