Skip to content

Instantly share code, notes, and snippets.

@tigt
Created April 21, 2022 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tigt/97448740d829d8dd341413086d1595f3 to your computer and use it in GitHub Desktop.
Save tigt/97448740d829d8dd341413086d1595f3 to your computer and use it in GitHub Desktop.
Sample Rollup config for Marko, Sass, Babel, Autoprefixer, & Browserslist
import { builtinModules } from 'module'
import path from 'path'
import autoprefixer from 'autoprefixer'
import babelPlugin from '@rollup/plugin-babel'
import commonjsPlugin from '@rollup/plugin-commonjs'
import copyPlugin from 'rollup-plugin-copy'
import jsonPlugin from '@rollup/plugin-json'
import markoPlugin from '@marko/rollup'
import nodeResolvePlugin from '@rollup/plugin-node-resolve'
import replacePlugin from '@rollup/plugin-replace'
import runPlugin from '@rollup/plugin-run'
import stylesPlugin from 'rollup-plugin-styles'
import urlPlugin from '@rollup/plugin-url'
import pkg from './package.json'
const __DEV__ = process.env.NODE_ENV === 'development'
const __PROD__ = !__DEV__
const isWatch = Boolean(process.env.ROLLUP_WATCH)
const publicPath = '/s/' // Guess what character is only 5 bits under HPACK
const assetFileNames = '[name]-[hash][extname]'
const bundleAnalyzerFilename = 'built/bundle.html'
const externalDependencies = [...Object.keys(pkg.dependencies), ...builtinModules]
process.env.SASS_PATH = './:./node_modules'
export default (async () => [
compiler('server', {
input: 'index.js',
output: {
dir: 'built/server/',
assetFileNames: `../browser/${assetFileNames}`,
format: 'cjs',
sourcemap: true
},
external: id => externalDependencies.some(dependency =>
id === dependency || id.startsWith(dependency + '/')
),
plugins: [
isWatch && runPlugin({ execArgv: ['--enable-source-maps'] })
]
}),
compiler('browser', {
output: {
dir: 'built/browser/',
chunkFileNames: __PROD__ ? '[name]-[hash].js' : null,
entryFileNames: __PROD__ ? '[name]-[hash].js' : null,
assetFileNames,
sourcemap: true,
sourcemapExcludeSources: __PROD__
},
manualChunks (id) {
if (isComponents(id, 'Page', 'Button')) {
return 'site'
}
},
plugins: [
stylesPlugin({
mode: 'extract',
sourceMap: true,
config: {
target: 'browserslist:css',
plugins: [
autoprefixer({ env: 'css' })
]
},
minimize: __PROD__,
url: {
publicPath,
hash: assetFileNames
}
}),
copyPlugin({
targets: [{
src: ['routes/_eternal-urls/**.*', '!**/*.md'],
dest: 'built/browser/_eternal-urls/'
}]
}),
__PROD__ && (await import('rollup-plugin-terser')).terser(),
__PROD__ && (await import('rollup-plugin-gzip')).default({
filter: /\.(?:js|css|svg|json|xml|txt)$/,
additionalFiles: ['built/browser/_eternal-urls/favicon.ico'], // Sadly this doesn’t “just work” with rollup-plugin-copy, so…
minSize: 1024,
gzipOptions: {
level: 9,
memLevel: 9
}
}),
__PROD__ && !isWatch && (await import('rollup-plugin-visualizer')).default({
title: `${(new Date()).toLocaleTimeString('en-GB')} ⚓️ JS Bundle`,
filename: bundleAnalyzerFilename
}),
__PROD__ && !isWatch && {
name: 'bundle-visualizer-location',
writeBundle () {
console.info(`📊 Bundle visualizer at \x1b[4;36mfile://${path.join(__dirname, '../../', bundleAnalyzerFilename)}\x1b[0m`)
}
}
]
})
])()
function compiler (target, config) {
const isBrowser = target === 'browser'
const browserslistEnv = isBrowser ? 'js' : 'server'
const babelConfig = {
comments: false,
browserslistEnv,
compact: false,
babelrc: false,
caller: { target }
}
if (isBrowser) {
babelConfig.presets = [
['@babel/preset-env', {
browserslistEnv,
bugfixes: true
}]
]
}
return {
...config,
preserveEntrySignatures: false,
plugins: [
markoPlugin[target]({
babelConfig,
serialize (output) {
return output.filter(({ fileName }) => /\.(?:css|js)$/.test(fileName))
.map(chunk => {
const data = (chunk.code || chunk.source)
.trim()
.replace(/^\s+$/, '')
return {
name: chunk.name,
imports: chunk.imports,
fileName: chunk.fileName,
inline: chunk.fileName.endsWith('.css') && data.replace(/\n\/\*# sourceMappingURL=.+ \*\//, '')
}
})
}
}),
nodeResolvePlugin({
browser: isBrowser,
preferBuiltins: !isBrowser
}),
commonjsPlugin(),
replacePlugin({
preventAssignment: true,
values: { __DEV__, __PROD__ }
}),
babelPlugin({
babelHelpers: 'bundled',
...babelConfig
}),
jsonPlugin(),
urlPlugin({
publicPath,
destDir: 'built/browser/',
fileName: assetFileNames,
include: '**/*.{svg,png,jpg,jpeg}',
limit: 0, // Never Base64 & inline
emitFiles: !isBrowser
}),
...config.plugins
]
}
}
function isComponents (id, ...names) {
return names.some(name => id.includes(`components/${name}/`))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment