feat: precompile assets on build (#2091)
This commit is contained in:
Родитель
053e634f97
Коммит
7eea09be86
|
@ -9,3 +9,4 @@ css/**/*.css
|
|||
yarn.lock
|
||||
cypress/videos/*
|
||||
/public/styles/octicons/octicons.html
|
||||
/precompiled/
|
||||
|
|
|
@ -2,7 +2,8 @@ require('require-yaml')
|
|||
|
||||
const i18n = require('electron-i18n')
|
||||
const flat = require('flat')
|
||||
const { get, set } = require('lodash')
|
||||
const get = require('lodash/get')
|
||||
const set = require('lodash/set')
|
||||
const locales = Object.keys(i18n.locales)
|
||||
const websiteStrings = require('../data/locale.yml')
|
||||
const websiteKeys = Object.keys(flat(websiteStrings))
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
const nodeModulesToAvoidBabelifying = [
|
||||
'lodash',
|
||||
'lunr',
|
||||
'prettydate'
|
||||
]
|
||||
|
||||
const excludeRegex = new RegExp(`/node_modules/(${nodeModulesToAvoidBabelifying.join('|')})`)
|
||||
|
||||
module.exports = function doBrowserify (browserify) {
|
||||
return function (entry) {
|
||||
return browserify(entry, {
|
||||
transform: [
|
||||
['babelify', {
|
||||
global: true,
|
||||
exclude: excludeRegex,
|
||||
presets: [
|
||||
['@babel/preset-env', { targets: '> 0.25%, not dead' }]
|
||||
]
|
||||
}],
|
||||
'brfs'
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,4 @@
|
|||
const browserify = require('browserify-middleware')
|
||||
const browserifyOptions = require('./browserify-opts')
|
||||
|
||||
const nodeModulesToAvoidBabelifying = [
|
||||
'lodash',
|
||||
'lunr',
|
||||
'prettydate'
|
||||
]
|
||||
|
||||
const excludeRegex = new RegExp(`/node_modules/(${nodeModulesToAvoidBabelifying.join('|')})`)
|
||||
|
||||
function babelifyMiddleware (entry) {
|
||||
return browserify(entry, {
|
||||
transform: [
|
||||
['babelify', {
|
||||
global: true,
|
||||
exclude: excludeRegex,
|
||||
presets: [
|
||||
['@babel/preset-env', { targets: '> 0.25%, not dead' }]
|
||||
]
|
||||
}],
|
||||
'brfs'
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = babelifyMiddleware
|
||||
module.exports = browserifyOptions(browserify)
|
||||
|
|
|
@ -13590,7 +13590,6 @@
|
|||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
|
||||
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"commander": "~2.17.1",
|
||||
"source-map": "~0.6.1"
|
||||
|
@ -13599,14 +13598,12 @@
|
|||
"commander": {
|
||||
"version": "2.17.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
|
||||
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
|
||||
"optional": true
|
||||
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"optional": true
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -15,10 +15,12 @@
|
|||
"release": "node script/release",
|
||||
"dev": "cross-env NODE_PATH=. NODE_ENV=development nodemon server.js",
|
||||
"prepack": "check-for-leaks",
|
||||
"precompile-assets": "cross-env NODE_ENV=production node script/precompile-assets.js",
|
||||
"linkschecker": "NODE_PATH=. NODE_ENV=test node scripts/links-checker.js",
|
||||
"cypress": "cypress run",
|
||||
"lint": "standard --fix",
|
||||
"generate-octicons": "node ./script/generate-octicons.js"
|
||||
"generate-octicons": "node ./script/generate-octicons.js",
|
||||
"heroku-postbuild": "npm run precompile-assets"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
@ -99,6 +101,7 @@
|
|||
"standard": "^12.0.1",
|
||||
"supertest": "^3.4.2",
|
||||
"supertest-session": "^3.3.0",
|
||||
"uglify-js": "^3.4.9",
|
||||
"wait-on": "^3.1.0",
|
||||
"walk-sync": "^1.1.3"
|
||||
},
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
npm run precompile-assets
|
||||
npm start &
|
||||
wait-on http://localhost:5000
|
||||
cypress run --record --key a0cba5c6-0650-4abe-8d41-d990bb7a0a66
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
const path = require('path')
|
||||
const stream = require('stream')
|
||||
const fs = require('fs-extra')
|
||||
const browserify = require('browserify')
|
||||
const browserifyOptions = require('../middleware/browserify-opts')
|
||||
const sass = require('node-sass')
|
||||
const uglify = require('uglify-js')
|
||||
|
||||
function dir (...parts) {
|
||||
return path.join(__dirname, '..', ...parts)
|
||||
}
|
||||
|
||||
function uglifyStream () {
|
||||
const buffers = []
|
||||
return new stream.Transform({
|
||||
transform (chunk, _encoding, callback) {
|
||||
buffers.push(chunk)
|
||||
callback()
|
||||
},
|
||||
|
||||
flush (callback) {
|
||||
const code = Buffer.concat(buffers).toString()
|
||||
const compiled = uglify.minify(code)
|
||||
this.push(compiled.code)
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const PATHS = {
|
||||
precompiled: dir('precompiled'),
|
||||
scripts: dir('precompiled', 'scripts'),
|
||||
styles: dir('precompiled', 'styles'),
|
||||
nodeModules: dir('node_modules'),
|
||||
|
||||
jsEntry: dir('scripts', 'index.js'),
|
||||
jsDestination: dir('precompiled', 'scripts', 'index.js'),
|
||||
|
||||
cssEntry: dir('public', 'styles', 'index.scss'),
|
||||
cssDestination: dir('precompiled', 'styles', 'index.css')
|
||||
}
|
||||
|
||||
async function precompileAssets () {
|
||||
try {
|
||||
console.log('Creating directories...')
|
||||
await fs.remove(PATHS.precompiled)
|
||||
await fs.ensureDir(PATHS.scripts)
|
||||
await fs.ensureDir(PATHS.styles)
|
||||
console.log('Precompiling JS...')
|
||||
await precompileJavaScript()
|
||||
console.log('Precompiling CSS...')
|
||||
await precompileCss()
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
function precompileJavaScript () {
|
||||
return new Promise((resolve, reject) => {
|
||||
const b = browserifyOptions(browserify)(PATHS.jsEntry)
|
||||
const pipe = b.bundle()
|
||||
.pipe(uglifyStream())
|
||||
.pipe(fs.createWriteStream(PATHS.jsDestination))
|
||||
pipe.on('error', reject)
|
||||
pipe.on('finish', resolve)
|
||||
})
|
||||
}
|
||||
|
||||
function precompileCss () {
|
||||
return new Promise((resolve, reject) => {
|
||||
sass.render({
|
||||
file: PATHS.cssEntry,
|
||||
includePaths: [
|
||||
PATHS.nodeModules
|
||||
]
|
||||
}, async function onSassCompiled (err, result) {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
await fs.writeFile(PATHS.cssDestination, result.css)
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
precompileAssets()
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
const { escapeRegExp } = require('lodash')
|
||||
const escapeRegExp = require('lodash/escapeRegExp')
|
||||
|
||||
module.exports = function applyActiveClassToActiveLinks () {
|
||||
const topPath = `/${location.pathname.split('/')[1]}`
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { debounce } = require('lodash')
|
||||
const debounce = require('lodash/debounce')
|
||||
const lunr = require('lunr')
|
||||
const queryString = require('query-string')
|
||||
const setQueryString = require('set-query-string')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const { throttle } = require('lodash')
|
||||
const throttle = require('lodash/throttle')
|
||||
|
||||
function inViewport (element) {
|
||||
const { top, right, bottom, left } = element.getBoundingClientRect()
|
||||
|
|
10
server.js
10
server.js
|
@ -45,8 +45,14 @@ app.set('views', path.join(__dirname, '/views'))
|
|||
app.use(nakedRedirect(true, 'www', 302))
|
||||
app.use(compression())
|
||||
app.use(helmet())
|
||||
app.use(sass())
|
||||
app.use('/scripts/index.js', browserify('scripts/index.js'))
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log('Production app detected; serving JS and CSS from disk')
|
||||
app.use(express.static(path.join(__dirname, 'precompiled'), { redirect: false }))
|
||||
} else {
|
||||
console.log('Dev app detected; compiling JS and CSS in memory')
|
||||
app.use(sass())
|
||||
app.use('/scripts/index.js', browserify('scripts/index.js'))
|
||||
}
|
||||
app.get('/service-worker.js', (req, res) => res.sendFile(path.resolve(__dirname, 'scripts', 'service-worker.js')))
|
||||
app.use(cookieParser())
|
||||
app.use(requestLanguage({
|
||||
|
|
|
@ -8,7 +8,7 @@ const fs = require('fs')
|
|||
const path = require('path')
|
||||
const walk = require('walk-sync')
|
||||
const flat = require('flat')
|
||||
const getProp = require('lodash').get
|
||||
const getProp = require('lodash/get')
|
||||
|
||||
const locale = require(path.join(__dirname, '../data/locale.yml'))
|
||||
const views = walk.entries(path.join(__dirname, '../views'))
|
||||
|
|
Загрузка…
Ссылка в новой задаче