build: use hashed assets for CSS and JS in prod (#5190)
This commit is contained in:
Родитель
b49759c3f9
Коммит
396dc6bdd6
|
@ -17517,6 +17517,40 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"webpack-manifest-plugin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-3.0.0.tgz",
|
||||
"integrity": "sha512-nbORTdky2HxD8XSaaT+zrsHb30AAgyWAWgCLWaAeQO21VGCScGb52ipqlHA/njix1Z8OW8IOlo4+XK0OKr1fkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tapable": "^2.0.0",
|
||||
"webpack-sources": "^2.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"tapable": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
|
||||
"integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
|
||||
"dev": true
|
||||
},
|
||||
"webpack-sources": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz",
|
||||
"integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-list-map": "^2.0.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-sources": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
"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 webpack --config ./webpack.common.js && node script/precompile-assets.js",
|
||||
"precompile-assets": "rimraf precompiled && cross-env NODE_ENV=production webpack --config ./webpack.common.js && node script/precompile-assets.js",
|
||||
"linkschecker": "NODE_PATH=. NODE_ENV=test node scripts/links-checker.js",
|
||||
"cypress": "cypress run",
|
||||
"lint": "npm run lint:js && npm run lint:style",
|
||||
|
@ -110,6 +110,7 @@
|
|||
"node-sass": "^5.0.0",
|
||||
"nodemon": "^2.0.7",
|
||||
"prettier": "^2.2.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"simplecrawler": "^1.1.9",
|
||||
"stylelint": "^13.11.0",
|
||||
"stylelint-config-standard": "^20.0.0",
|
||||
|
@ -120,7 +121,8 @@
|
|||
"walk-sync": "^2.2.0",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-cli": "^3.3.12",
|
||||
"webpack-dev-middleware": "^4.1.0"
|
||||
"webpack-dev-middleware": "^4.1.0",
|
||||
"webpack-manifest-plugin": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12 <14"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
const crypto = require('crypto')
|
||||
const path = require('path')
|
||||
const fs = require('fs-extra')
|
||||
const sass = require('node-sass')
|
||||
|
@ -6,13 +7,15 @@ function dir(...parts) {
|
|||
return path.join(__dirname, '..', ...parts)
|
||||
}
|
||||
|
||||
const env = process.env.NODE_ENV
|
||||
|
||||
const PATHS = {
|
||||
precompiled: dir('precompiled'),
|
||||
styles: dir('precompiled', 'styles'),
|
||||
nodeModules: dir('node_modules'),
|
||||
|
||||
cssEntry: dir('public', 'styles', 'index.scss'),
|
||||
cssDestination: dir('precompiled', 'styles', 'index.css'),
|
||||
cssDestinationDir: dir('precompiled', 'styles'),
|
||||
}
|
||||
|
||||
async function precompileAssets() {
|
||||
|
@ -40,7 +43,19 @@ function precompileCss() {
|
|||
return reject(err)
|
||||
}
|
||||
|
||||
await fs.writeFile(PATHS.cssDestination, result.css)
|
||||
const cssHash = crypto
|
||||
.createHash('md4')
|
||||
.update(result.css)
|
||||
.digest('hex')
|
||||
const cssFileName =
|
||||
env === 'production' ? `index.${cssHash}.min.css` : 'index.css'
|
||||
const cssFile = path.resolve(PATHS.cssDestinationDir, cssFileName)
|
||||
|
||||
await fs.writeFile(cssFile, result.css)
|
||||
await fs.writeFile(
|
||||
path.resolve(PATHS.cssDestinationDir, 'manifest.json'),
|
||||
JSON.stringify({ 'index.css': `/styles/${cssFileName}` }, null, 2)
|
||||
)
|
||||
resolve()
|
||||
}
|
||||
)
|
||||
|
@ -48,5 +63,8 @@ function precompileCss() {
|
|||
}
|
||||
|
||||
if (require.main === module) {
|
||||
precompileAssets()
|
||||
precompileAssets().catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
|
33
server.js
33
server.js
|
@ -77,6 +77,39 @@ app.use(
|
|||
referrerPolicy: false,
|
||||
})
|
||||
)
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
const jsManifest = require(path.join(
|
||||
__dirname,
|
||||
'precompiled',
|
||||
'scripts',
|
||||
'manifest.json'
|
||||
))
|
||||
const cssManifest = require(path.join(
|
||||
__dirname,
|
||||
'precompiled',
|
||||
'styles',
|
||||
'manifest.json'
|
||||
))
|
||||
hbs.registerHelper('static-asset', (type, name) => {
|
||||
if (type === 'js') {
|
||||
return jsManifest[name] || 'unknown.name'
|
||||
}
|
||||
if (type === 'css') {
|
||||
return cssManifest[name] || 'unknown.name'
|
||||
}
|
||||
return 'unknown.type'
|
||||
})
|
||||
} else {
|
||||
hbs.registerHelper('static-asset', (type, name) => {
|
||||
if (type === 'js') {
|
||||
return `/scripts/${name}`
|
||||
}
|
||||
if (type === 'css') {
|
||||
return `/styles/${name}`
|
||||
}
|
||||
return 'unknown.type'
|
||||
})
|
||||
}
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
console.log('Production app detected; serving JS and CSS from disk')
|
||||
app.use(
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
})
|
||||
}
|
||||
</script>
|
||||
<script src="/scripts/index.js"></script>
|
||||
<script src="{{static-asset "js" "index.js"}}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
<link rel='shortcut icon' href='/images/favicon.ico'/>
|
||||
<link rel="alternate" type="application/rss+xml" title="Electron Blog" href="https://electronjs.org/blog.xml" />
|
||||
<link rel="alternate" type="application/rss+xml" title="Electron Releases" href="https://electronjs.org/releases.xml" />
|
||||
<link rel='stylesheet' href='/styles/index.css'>
|
||||
<link rel='stylesheet' href='{{static-asset "css" "index.css"}}'>
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
const path = require('path')
|
||||
const { WebpackManifestPlugin } = require('webpack-manifest-plugin')
|
||||
|
||||
const env = process.env.NODE_ENV
|
||||
|
||||
module.exports = {
|
||||
entry: { index: './scripts/index.js' },
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
filename: env === 'production' ? '[name].[chunkhash].min.js' : '[name].js',
|
||||
path: path.resolve(__dirname, 'precompiled', 'scripts'),
|
||||
publicPath: '/scripts/',
|
||||
},
|
||||
|
@ -14,6 +15,8 @@ module.exports = {
|
|||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
|
||||
plugins: [new WebpackManifestPlugin()],
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче