/**
* Copyright 2020 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import * as path from 'path';
import { promises as fsp } from 'fs';
import del from 'del';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { terser } from 'rollup-plugin-terser';
import OMT from '@surma/rollup-plugin-off-main-thread';
import replace from '@rollup/plugin-replace';
import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets';
import simpleTS from './lib/simple-ts';
import clientBundlePlugin from './lib/client-bundle-plugin';
import nodeExternalPlugin from './lib/node-external-plugin';
import cssPlugin from './lib/css-plugin';
import urlPlugin from './lib/url-plugin';
import resolveDirsPlugin from './lib/resolve-dirs-plugin';
import runScript from './lib/run-script';
import emitFiles from './lib/emit-files-plugin';
import featurePlugin from './lib/feature-plugin';
import initialCssPlugin from './lib/initial-css-plugin';
import serviceWorkerPlugin from './lib/sw-plugin';
import dataURLPlugin from './lib/data-url-plugin';
import entryDataPlugin, { fileNameToURL } from './lib/entry-data-plugin';
import dedent from 'dedent';
function resolveFileUrl({ fileName }) {
return JSON.stringify(fileNameToURL(fileName));
}
function resolveImportMetaUrlInStaticBuild(property, { moduleId }) {
if (property !== 'url') return;
throw new Error(dedent`
Attempted to use a \`new URL(..., import.meta.url)\` pattern in ${path.relative(
process.cwd(),
moduleId,
)} for URL that needs to end up in static HTML.
This is currently unsupported.
`);
}
const dir = '.tmp/build';
const staticPath = 'static/c/[name]-[hash][extname]';
const jsPath = staticPath.replace('[extname]', '.js');
function jsFileName(chunkInfo) {
if (!chunkInfo.facadeModuleId) return jsPath;
const parsedPath = path.parse(chunkInfo.facadeModuleId);
if (parsedPath.name !== 'index') return jsPath;
// Come up with a better name than 'index'
const name = parsedPath.dir.split(/\\|\//).slice(-1);
return jsPath.replace('[name]', name);
}
export default async function ({ watch }) {
const omtLoaderPromise = fsp.readFile(
path.join(__dirname, 'lib', 'omt.ejs'),
'utf-8',
);
await del('.tmp/build');
const isProduction = !watch;
const tsPluginInstance = simpleTS('.', {
watch,
});
const commonPlugins = () => [
tsPluginInstance,
resolveDirsPlugin([
'src/static-build',
'src/client',
'src/shared',
'src/features',
'src/features-worker',
'src/features-worker-worker-bridge',
'src/sw',
'codecs',
]),
urlPlugin(),
dataURLPlugin(),
cssPlugin(),
];
return {
input: 'src/static-build/index.tsx',
output: {
dir,
format: 'cjs',
assetFileNames: staticPath,
exports: 'named',
},
watch: {
clearScreen: false,
// Don't watch the ts files. Instead we watch the output from the ts compiler.
exclude: ['**/*.ts', '**/*.tsx'],
// Sometimes TypeScript does its thing a little slowly, which causes
// Rollup to build twice on each change. This delay seems to fix it,
// although we may need to change this number over time.
buildDelay: 250,
},
preserveModules: true,
plugins: [
{ resolveFileUrl, resolveImportMeta: resolveImportMetaUrlInStaticBuild },
clientBundlePlugin(
{
external: ['worker_threads'],
plugins: [
{ resolveFileUrl },
OMT({ loader: await omtLoaderPromise }),
importMetaAssets(),
serviceWorkerPlugin({
output: 'static/serviceworker.js',
}),
...commonPlugins(),
commonjs(),
resolve(),
replace({ __PRERENDER__: false, __PRODUCTION__: isProduction }),
entryDataPlugin(),
isProduction ? terser({ module: true }) : {},
],
preserveEntrySignatures: false,
},
{
dir,
format: 'amd',
chunkFileNames: jsFileName,
entryFileNames: jsFileName,
// This is needed because emscripten's workers use 'this', so they trigger all kinds of interop things,
// such as double-wrapping objects in { default }.
interop: false,
},
resolveFileUrl,
),
...commonPlugins(),
emitFiles({ include: '**/*', root: path.join(__dirname, 'src', 'copy') }),
nodeExternalPlugin(),
featurePlugin(),
replace({ __PRERENDER__: true, __PRODUCTION__: isProduction }),
initialCssPlugin(),
runScript(dir + '/static-build/index.js'),
],
};
}