Skip to content

Commit

Permalink
chore: 构建优化
Browse files Browse the repository at this point in the history
style: lint 增强(by升级插件)
  • Loading branch information
Maorey committed Nov 22, 2019
1 parent 73bd838 commit a2c9afd
Show file tree
Hide file tree
Showing 15 changed files with 426 additions and 259 deletions.
130 changes: 125 additions & 5 deletions build/insertPreload.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,79 @@
* 依赖:
* https://github.com/jantimon/html-webpack-plugin
* @vue/preload-webpack-plugin (fork:https://github.com/GoogleChromeLabs/preload-webpack-plugin)
* 合并: https://github.com/szrenwei/inline-manifest-webpack-plugin
* @Author: Maorey
* @Date: 2019-01-17 11:42:24
*/
const sourceMappingURL = require('source-map-url')

const PLUGIN_NAME = 'insert-preload'

function getAssetName(chunks, reg) {
const match = []
for (let chunk of chunks) {
reg.test(chunk.name) &&
match.push({ name: chunk.name, file: chunk.files[0] })
}
return match
}
function inlineWhenMatched(compilation, scripts, manifestAssetNames) {
return scripts.map(script => {
if (script.tagName === 'script') {
const src = script.attributes.src
for (let item of manifestAssetNames) {
if (src.indexOf(item.file) >= 0) {
return {
tagName: 'script',
closeTag: true,
attributes: {
type: 'text/javascript',
},
innerHTML: sourceMappingURL.removeFrom(
compilation.assets[item.file].source(),
),
}
}
}
}

return script
})
}

/** 插入 preload 的资源插件
*/
module.exports = class {
/**
* @param {Object} option 选项
* {
* runtime:String 待移除preload的runtime名
* falsy: 不移除, true = 'runtime', String: 指定名字
* runtime:String|Array<String>|RegExp 内联runtime
* defer:Boolean 脚本是否defer 默认true
* async:Boolean 脚本是否async 默认false (和defer只能有一个)
* }
*/
constructor(option = {}) {
let runtime = option.runtime
runtime === true && (runtime = 'runtime')
this._REG_REMOVE = runtime && new RegExp(`(?:[\\/]|^)${runtime}\\..*\\.js$`)
if (runtime) {
if (typeof runtime.test === 'function') {
this._REG_RUNTIME = runtime
} else {
typeof runtime === 'string' && (runtime = [runtime])
for (let i = 0; i < runtime.length; i++) {
runtime[i] = new RegExp(runtime[i])
}
this._REG_RUNTIME = {
test(str) {
for (let reg of runtime) {
if (reg.test(str)) {
return true
}
}
return false
},
}
}
}
this._SA =
option.defer === false ? option.async === true && 'async' : 'defer'
}
Expand All @@ -42,6 +93,75 @@ module.exports = class {
htmlPluginData => this.insert(htmlPluginData),
),
)
// inline-manifest
const REG_RUNTIME = this._REG_RUNTIME
if (REG_RUNTIME) {
compiler.hooks.emit.tap(PLUGIN_NAME, compilation => {
for (let item of getAssetName(compilation.chunks, REG_RUNTIME)) {
delete compilation.assets[item.file]
}
})
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(
PLUGIN_NAME,
(data, cb) => {
const manifestAssetNames = getAssetName(
compilation.chunks,
REG_RUNTIME,
)

manifestAssetNames.length &&
['head', 'body'].forEach(section => {
data[section] = inlineWhenMatched(
compilation,
data[section],
manifestAssetNames,
)
})

cb(null, data)
},
)

compilation.hooks.htmlWebpackPluginBeforeHtmlGeneration.tapAsync(
PLUGIN_NAME,
(htmlPluginData, cb) => {
const runtime = []
const assets = htmlPluginData.assets
const manifestAssetNames = getAssetName(
compilation.chunks,
REG_RUNTIME,
)

if (
manifestAssetNames.length &&
htmlPluginData.plugin.options.inject === false
) {
for (let item of manifestAssetNames) {
runtime.push('<script>')
runtime.push(
sourceMappingURL.removeFrom(
compilation.assets[item.file].source(),
),
)
runtime.push('</script>')

const runtimeIndex = assets.js.indexOf(
assets.publicPath + item.file,
)
if (runtimeIndex >= 0) {
assets.js.splice(runtimeIndex, 1)
delete assets.chunks[item.name]
}
}
}

assets.runtime = runtime.join('')
cb(null, htmlPluginData)
},
)
})
}
// 不能这么加loader
// const REG_EXCLUDE = /[\\/]node_modules[\\/]/
// const REG_INCLUDE = /\.(?:ts|vue|tsx|js|jsx)$/
Expand All @@ -67,7 +187,7 @@ module.exports = class {

const script = 'script'
const relStyle = 'stylesheet'
const REG_RUNTIME = this._REG_REMOVE
const REG_RUNTIME = this._REG_RUNTIME

const SCRIPT_ATTRIBUTE = this._SA
let el
Expand Down
86 changes: 53 additions & 33 deletions build/production.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* @Date: 2019-04-01 13:28:06
*/
const path = require('path')
const RUNTIME_CHUNK = 'runtime'

const getLoaderOption = name => ({
limit: 4096,
Expand Down Expand Up @@ -43,7 +42,7 @@ function fileName(config) {
.options(getLoaderOption('media/' + FileName))
}

function plugin(config, DIR) {
function plugin(config, DIR, pages) {
// 【弃 过时但有效】固定打包文件哈希, 避免相同代码打包出不同哈希
// (排除 boilerplate(runtime and manifest)等影响)
// config.plugin('md5-hash').use('webpack-md5-hash')
Expand All @@ -55,12 +54,17 @@ function plugin(config, DIR) {
config
.plugin('insert-preload')
.use(path.join(DIR, 'build/insertPreload.js'), [
{ runtime: RUNTIME_CHUNK, defer: true },
{
runtime: (() => {
const RUNTIMES = []
for (const entry in pages) {
RUNTIMES.push(entry + '_')
}
return RUNTIMES
})(),
defer: true,
},
])
// runtime Chunk 内联到html
config
.plugin('inline-manifest')
.use('inline-manifest-webpack-plugin', [RUNTIME_CHUNK])
// 文件 gzip 压缩 https://webpack.docschina.org/plugins/compression-webpack-plugin/
config.plugin('gzip').use('compression-webpack-plugin', [
{
Expand All @@ -84,9 +88,10 @@ function plugin(config, DIR) {
/** webpack 配置
* @param {chainWebpack} config 配置对象
* @param {Object} ENV 环境变量
* @param {Object} pages 入口
* https://github.com/neutrinojs/webpack-chain#getting-started
*/
module.exports = function(config, ENV) {
module.exports = function(config, ENV, pages) {
const DIR = process.cwd()
config.merge({
// https://webpack.js.org/configuration/other-options/#recordspath
Expand Down Expand Up @@ -117,11 +122,11 @@ module.exports = function(config, ENV) {
// .loader(loader)
// }
fileName(config)
plugin(config, DIR)
plugin(config, DIR, pages)

/// 【优化(optimization)】 ///
// https://webpack.docschina.org/configuration/optimization 默认就好
config.optimization.runtimeChunk({ name: RUNTIME_CHUNK })
config.optimization.runtimeChunk({ name: o => o.name + '_' })

/// 【代码分割(optimization.splitChunks 不能config.merge({}))】 ///
// https://webpack.docschina.org/plugins/split-chunks-plugin
Expand Down Expand Up @@ -168,14 +173,37 @@ module.exports = function(config, ENV) {
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]core-js(?:-pure)?[\\/]/,
},
// configs (每个页面分开应无必要)
// configs
conf: {
name: 'conf',
chunks: 'all',
enforce: true, // 确保会创建这个chunk (否则可能会根据splitChunks选项被合并/拆分)
priority: 666,
test: /[\\/]config[\\/]/,
priority: 66,
test: /src[\\/](?:[^\\/]+[\\/])*config[\\/]/,
},
// 各入口的配置文件
...(() => {
const group = {}
const prefix = 'conf.'
const REG = /[\\/]/g
const STR = '[\\\\/]'
const STR_ = '[^\\\\/]'
const REG_SUB = /[^\\/]+$/
let name
let entry
for (name in pages) {
entry = pages[name].entry.replace(REG_SUB, '').replace(REG, STR)
name = prefix + name
group[name] = {
name,
chunks: 'all',
enforce: true,
priority: 666,
test: new RegExp(`${entry}(?:${STR_}+${STR})*config${STR}`),
}
}
return group
})(),
// json文件 (-> json.*.*.js)
// json: {
// name: 'json',
Expand All @@ -184,21 +212,13 @@ module.exports = function(config, ENV) {
// priority: 668,
// test: /[\\/]?.+\.json(?:[^\w].*)?$/, // 或者 type: 'json'
// },
// vue
v: {
name: 'v',
chunks: 'all',
enforce: true,
priority: 66,
test: /[\\/]node_modules[\\/]vue[\\/]/,
},
// vue全家桶全搜集 (vuex/vue-router...)
vf: {
name: 'vf',
// vue全搜集 (vue/vuex/vue-router...)
vue: {
name: 'vue',
chunks: 'all',
priority: 66,
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]vue.+[\\/]/,
test: /[\\/]node_modules[\\/]vue.*[\\/]/,
},
// elementUI (建议按需引入)
eui: {
Expand All @@ -208,14 +228,6 @@ module.exports = function(config, ENV) {
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]element-ui[\\/]/,
},
// d3.js
d3: {
name: 'd3',
chunks: 'all',
priority: 66,
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]d3[\\/]/,
},
// zrender (二维绘图引擎)
zrd: {
name: 'zrd',
Expand All @@ -232,6 +244,14 @@ module.exports = function(config, ENV) {
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]echarts[\\/]/,
},
// d3.js
d3: {
name: 'd3',
chunks: 'all',
priority: 66,
reuseExistingChunk: true,
test: /[\\/]node_modules[\\/]d3[\\/]/,
},
// zdog
zdg: {
name: 'zdg',
Expand Down
19 changes: 11 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
},
"dependencies": {
"axios": "^0.19.0",
"core-js": "^3.4.1",
"core-js": "^3.4.2",
"crypto-js": "^3.1.9-1",
"d3": "^5.14.1",
"echarts": "^4.4.0",
"echarts": "^4.5.0",
"element-ui": "^2.12.0",
"jsencrypt": "^3.0.0-rc.1",
"luma.gl": "^7.3.2",
Expand All @@ -58,8 +58,8 @@
"@types/d3": "^5.7.2",
"@types/echarts": "^4.4.1",
"@types/jest": "^24.0.23",
"@typescript-eslint/eslint-plugin": "^2.7.0",
"@typescript-eslint/parser": "^2.7.0",
"@typescript-eslint/eslint-plugin": "^2.8.0",
"@typescript-eslint/parser": "^2.8.0",
"@vue/cli-plugin-babel": "^4.0.5",
"@vue/cli-plugin-e2e-cypress": "^4.0.5",
"@vue/cli-plugin-eslint": "^4.0.5",
Expand All @@ -69,23 +69,26 @@
"@vue/cli-plugin-unit-jest": "^4.0.5",
"@vue/cli-plugin-vuex": "^4.0.5",
"@vue/cli-service": "^4.0.5",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/eslint-config-standard": "^5.0.0",
"@vue/eslint-config-typescript": "^5.0.0",
"@vue/test-utils": "^1.0.0-beta.29",
"compression-webpack-plugin": "^3.0.0",
"eslint": "^6.6.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-vue": "^6.0.1",
"fibers": "^4.0.2",
"inline-manifest-webpack-plugin": "^4.0.2",
"lint-staged": "^9.4.3",
"regenerate": "^1.4.0",
"regjsgen": "^0.5.1",
"regjsparser": "^0.6.0",
"sass": "^1.23.6",
"sass": "^1.23.7",
"sass-loader": "^8.0.0",
"stylelint": "^12.0.0",
"stylelint-config-scss-maorey": "^1.1.1",
"stylelint-webpack-plugin": "^1.0.4",
"stylelint-webpack-plugin": "^1.1.0",
"typescript": "^3.7.2",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.1.0",
Expand Down
Loading

0 comments on commit a2c9afd

Please sign in to comment.