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

Gatsby/modern builds #7

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 19 additions & 18 deletions packages/babel-preset-gatsby/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,28 @@ const resolve = m => require.resolve(m)
const loadCachedConfig = () => {
let pluginBabelConfig = {}
if (process.env.NODE_ENV !== `test`) {
try {
pluginBabelConfig = require(path.join(
process.cwd(),
`./.cache/babelState.json`
))
} catch (err) {
if (err.message.includes(`Cannot find module`)) {
// This probably is being used outside of the Gatsby CLI.
throw Error(
`\`babel-preset-gatsby\` has been loaded, which consumes config generated by the Gatsby CLI. Set \`NODE_ENV=test\` to bypass, or run \`gatsby build\` first.`
)
} else {
throw err
}
}
pluginBabelConfig = require(path.join(
process.cwd(),
`./.cache/babelState.json`
))
}
return pluginBabelConfig
}

const modernConfig = {
loose: true,
targets: {
esmodules: true,
},
useBuiltIns: false,
}

module.exports = function preset(_, options = {}) {
let { targets = null } = options
if (process.env.MODERN) {
options = modernConfig
}

let { targets = null, loose = true, useBuiltIns = `usage` } = options

const pluginBabelConfig = loadCachedConfig()
const stage = process.env.GATSBY_BUILD_STAGE || `test`
Expand All @@ -45,9 +46,9 @@ module.exports = function preset(_, options = {}) {
[
resolve(`@babel/preset-env`),
{
loose: true,
loose,
modules: stage === `test` ? `commonjs` : false,
useBuiltIns: `usage`,
useBuiltIns,
targets,
},
],
Expand Down
5 changes: 5 additions & 0 deletions packages/gatsby-cli/src/create-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ function buildLocalCommands(cli, isLocalSite) {
default: false,
describe: `Build site with link paths prefixed (set pathPrefix in your gatsby-config.js).`,
})
.option(`legacy`, {
type: `boolean`,
default: false,
describe: `Build site without modern (.mjs) build support`,
})
.option(`no-uglify`, {
type: `boolean`,
default: false,
Expand Down
72 changes: 36 additions & 36 deletions packages/gatsby/cache-dir/production-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ setApiRunnerForLoader(apiRunner)
navigationInit()

// Let the site/plugins run code very early.
apiRunnerAsync(`onClientEntry`).then(() => {
apiRunnerAsync(`onClientEntry`).then(async () => {
// Let plugins register a service worker. The plugin just needs
// to return true.
if (apiRunner(`registerServiceWorker`).length > 0) {
Expand Down Expand Up @@ -83,44 +83,44 @@ apiRunnerAsync(`onClientEntry`).then(() => {
)
}

loader.getResourcesForPathname(browserLoc.pathname).then(() => {
const Root = () =>
createElement(
Router,
{
basepath: __PATH_PREFIX__,
},
createElement(RouteHandler, { path: `/*` })
)
await loader.getResourcesForPathname(browserLoc.pathname)

const WrappedRoot = apiRunner(
`wrapRootElement`,
{ element: <Root /> },
<Root />,
({ result }) => {
return { element: result }
}
).pop()
const Root = () =>
createElement(
Router,
{
basepath: __PATH_PREFIX__,
},
createElement(RouteHandler, { path: `/*` })
)

const WrappedRoot = apiRunner(
`wrapRootElement`,
{ element: <Root /> },
<Root />,
({ result }) => {
return { element: result }
}
).pop()

let NewRoot = () => WrappedRoot
let NewRoot = () => WrappedRoot

const renderer = apiRunner(
`replaceHydrateFunction`,
undefined,
ReactDOM.hydrate
)[0]
const renderer = apiRunner(
`replaceHydrateFunction`,
undefined,
ReactDOM.hydrate
)[0]

domReady(() => {
renderer(
<NewRoot />,
typeof window !== `undefined`
? document.getElementById(`___gatsby`)
: void 0,
() => {
postInitialRenderWork()
apiRunner(`onInitialClientRender`)
}
)
})
domReady(() => {
renderer(
<NewRoot />,
typeof window !== `undefined`
? document.getElementById(`___gatsby`)
: void 0,
() => {
postInitialRenderWork()
apiRunner(`onInitialClientRender`)
}
)
})
})
45 changes: 37 additions & 8 deletions packages/gatsby/cache-dir/static-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -356,14 +356,43 @@ export default (pagePath, callback) => {
// Filter out prefetched bundles as adding them as a script tag
// would force high priority fetching.
const bodyScripts = scripts
.filter(s => s.rel !== `prefetch`)
.map(s => {
const scriptPath = `${__PATH_PREFIX__}/${JSON.stringify(s.name).slice(
1,
-1
)}`
return <script key={scriptPath} src={scriptPath} async />
})
.filter(script => script.rel !== `prefetch`)
.reduce((merged, script) => {
const scriptPath = `${__PATH_PREFIX__}/${JSON.stringify(
script.name
).slice(1, -1)}`
return merged.concat(
script.name.indexOf(`webpack-runtime`) === 0
? [
<script
key={scriptPath}
src={scriptPath.replace(`.js`, `-modern.js`)}
type="module"
async={true}
/>,
<script
key={scriptPath}
src={scriptPath}
noModule={true}
async={true}
/>,
]
: [
<script
key={scriptPath}
src={scriptPath.replace(`.js`, `.mjs`)}
type="module"
async={true}
/>,
<script
key={scriptPath}
src={scriptPath}
noModule={true}
async={true}
/>,
]
)
}, [])

postBodyComponents.push(...bodyScripts)

Expand Down
42 changes: 29 additions & 13 deletions packages/gatsby/src/commands/build-javascript.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
/* @flow */
const webpack = require(`webpack`)
const webpackConfig = require(`../utils/webpack.config`)
const getWebpackConfig = require(`../utils/webpack.config`)

module.exports = async program => {
const { directory } = program

const compilerConfig = await webpackConfig(
program,
directory,
`build-javascript`
)

return new Promise((resolve, reject) => {
webpack(compilerConfig).run((err, stats) => {
const build = config =>
new Promise((resolve, reject) => {
webpack(config).run((err, stats) => {
if (err) {
reject(err)
return
Expand All @@ -27,4 +18,29 @@ module.exports = async program => {
resolve()
})
})

// TODO: benchmark array of configs vs. running serially
// TODO: benchmark Promise.all vs. serial
module.exports = async program => {
const compilerConfig = await getWebpackConfig(
program,
program.directory,
`build-javascript`
)

await build(compilerConfig)

if (program.legacy === false) {
console.log(`building second bundle`)
await build(
await getWebpackConfig(
{
...program,
legacy: true,
},
program.directory,
`build-javascript`
)
)
}
}
1 change: 1 addition & 0 deletions packages/gatsby/src/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type BuildArgs = {
sitePackageJson: object,
prefixPaths: boolean,
noUglify: boolean,
legacy: boolean,
openTracingConfigFile: string,
}

Expand Down
19 changes: 9 additions & 10 deletions packages/gatsby/src/utils/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,13 @@ const hasLocalEslint = require(`./local-eslint-config-finder`)
// 3) build-javascript: Build JS and CSS chunks for production
// 4) build-html: build all HTML files

module.exports = async (
program,
directory,
suppliedStage,
webpackPort = 1500
) => {
module.exports = async (program, directory, suppliedStage) => {
const directoryPath = withBasePath(directory)

process.env.GATSBY_BUILD_STAGE = suppliedStage

const isModern = program.legacy === false

// We combine develop & develop-html stages for purposes of generating the
// webpack config.
const stage = suppliedStage
Expand Down Expand Up @@ -100,11 +97,12 @@ module.exports = async (

debug(`Loading webpack config for stage "${stage}"`)
function getOutput() {
const extension = isModern ? `mjs` : `js`
switch (stage) {
case `develop`:
return {
path: directory,
filename: `[name].js`,
filename: `[name].${extension}`,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// Point sourcemap entries to original disk location (format as URL on Windows)
Expand Down Expand Up @@ -132,8 +130,8 @@ module.exports = async (
}
case `build-javascript`:
return {
filename: `[name]-[contenthash].js`,
chunkFilename: `[name]-[contenthash].js`,
filename: `[name]-[contenthash].${extension}`,
chunkFilename: `[name]-[contenthash].${extension}`,
path: directoryPath(`public`),
publicPath: program.prefixPaths
? `${store.getState().config.pathPrefix}/`
Expand Down Expand Up @@ -386,8 +384,9 @@ module.exports = async (

if (stage === `build-javascript`) {
config.optimization = {
// TODO: configure extension of runtimeChunk
runtimeChunk: {
name: `webpack-runtime`,
name: `webpack-runtime${isModern ? `-modern` : ``}`,
},
splitChunks: {
name: false,
Expand Down
48 changes: 9 additions & 39 deletions packages/gatsby/src/utils/worker.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,9 @@
const fs = require(`fs-extra`)
const path = require(`path`)
const Promise = require(`bluebird`)

// copied from https://github.com/markdalgleish/static-site-generator-webpack-plugin/blob/master/index.js#L161
const generatePathToOutput = outputPath => {
let outputFileName = outputPath.replace(/^(\/|\\)/, ``) // Remove leading slashes for webpack-dev-server

if (!/\.(html?)$/i.test(outputFileName)) {
outputFileName = path.join(outputFileName, `index.html`)
}

return path.join(process.cwd(), `public`, outputFileName)
}

export function renderHTML({ htmlComponentRendererPath, paths, envVars }) {
// This is being executed in child process, so we need to set some vars
// for modules that aren't bundled by webpack.
envVars.forEach(([key, value]) => (process.env[key] = value))

return Promise.map(
paths,
path =>
new Promise((resolve, reject) => {
const htmlComponentRenderer = require(htmlComponentRendererPath)
try {
htmlComponentRenderer.default(path, (throwAway, htmlString) => {
resolve(fs.outputFile(generatePathToOutput(path), htmlString))
})
} catch (e) {
// add some context to error so we can display more helpful message
e.context = {
path,
}
reject(e)
}
})
)
}
const Worker = require(`jest-worker`).default
const numWorkers = require(`physical-cpu-count`) || 1

module.exports = new Worker(require.resolve(`./workers`), {
numWorkers,
forkOptions: {
silent: false,
},
})
Loading