共计 3914 个字符,预计需要花费 10 分钟才能阅读完成。
目录
[隐藏]
提醒:本文最后更新于2022-12-20 14:24,文中所关联的信息可能已发生改变,请知悉!
Angular-cli
通过 angular.json
实现构建配置,对于复杂配置需求的支持,可以通过 ng eject
输出 webpack 的配置文件,然后自定义 webpack 来达到目的。
当前对于 Angular 6.x/7.x
的项目,Angular-cli
需采用 6.x/7.x
版本,而这些版本不支持 ng eject
命令,于是希望自定义 webpack 配置实现更多复杂需求就无法下手。
1 自定义 Angular-cli 7.x 默认 webpack 的方案思路
由于 Angular-cli
内部是封装 webpack 来实现的,如果我们能够 hacker 一下,在其 webpack 配置封装过程中注入自定义配置,就也可以实现自定义需求。
按照这个思路,通过翻阅 Angular-cli 的源码,得到如下注入方法。该注入方法采用的 angular
相关工具链各版本为:
{ | |
"@angular-devkit/build-angular": "0.10.4", | |
"@angular/cli": "7.0.4" | |
} |
2 新建注入代码的脚本
新建注入代码的脚本 scripts/insert-to-cli-webpack.js
,内容参考:
const chalk = require('chalk'); | |
const fs = require('fs'); | |
const path = require('path'); | |
const rootDir = path.resolve(__dirname, '../'); | |
const buildNgSrcPathList = { | |
browser: path.resolve(__dirname, '../node_modules/@angular-devkit/build-angular/src/browser/index.js'), | |
karma: path.resolve(__dirname, '../node_modules/@angular-devkit/build-angular/src/karma/index.js'), | |
server: path.resolve(__dirname, '../node_modules/@angular-devkit/build-angular/src/server/index.js'), | |
}; | |
const webpackCliPath = path.resolve(__dirname, '../config/webpack-cli-inject.js').replace(/\\/g, '\\\\'); | |
const findStr = 'webpackMerge(webpackConfigs)'; | |
try { | |
Object.keys(buildNgSrcPathList).forEach(type => { | |
const filePath = buildNgSrcPathList[type]; | |
const filePathShort = filePath.replace(rootDir, ''); | |
const replaceStr = `require('${webpackCliPath}')(webpackMerge(webpackConfigs), wco, '${type}')`; | |
const configText = fs.readFileSync(filePath, 'utf-8'); | |
if (configText.includes(replaceStr)) { | |
return; | |
} | |
if (!configText.includes(findStr)) { | |
console.log(chalk.red.bold(`文件 ${chalk.yellow.bold(filePathShort)} 中未发现可替换的字符串: ${findStr}`)); | |
return; | |
} | |
console.log(chalk.yellow.bold(` Inserting to: `), chalk.yellow(filePathShort)); | |
const output = configText.replace(findStr, replaceStr); | |
fs.writeFileSync(filePath, output); | |
}); | |
console.log(chalk.green.bold(' well done!')); | |
} catch(err) { | |
console.log(err); | |
} |
3 新建自定义的 webpack 配置文件
如文件名为 config/webpack.cli-inject.js
,内容参考:
const webpackMerge = require('webpack-merge'); | |
const HtmlWebpackPlugin = require('html-webpack-plugin'); | |
const pkg = require('../package.json'); | |
const isProd = ENV === 'prod' || ENV === 'production'; | |
module.exports = (commonConfig, wco, cfgType) => { | |
const customCfg = { | |
module: { | |
rules: [ | |
{ | |
test: /\.pug$/, | |
use: [ | |
'raw-loader', | |
{ | |
loader: 'pug-html-loader', | |
options: { | |
doctype: 'html' | |
} | |
} | |
] | |
}, | |
// { | |
// test: /\.css$/, | |
// use: ['to-string-loader', { loader: 'css-loader', options: { url: false } }] | |
// }, | |
{ | |
test: /\.less$/, | |
use: [ 'style-loader', 'css-loader', 'sprites-loader', 'less-loader' ] | |
}, | |
] | |
}, | |
plugins: [ | |
/* | |
* See: https://github.com/ampedandwired/html-webpack-plugin | |
*/ | |
new HtmlWebpackPlugin({ | |
pkg: pkg, | |
// ----以上为自定义参数,用于模板中调用---- | |
xhtml: true, | |
template: 'src/index.html', | |
filename: 'index.html', | |
chunksSortMode: function(a, b) { | |
const entryPoints = ['inline', 'polyfills', 'sw-register', 'styles', 'vendor', 'main']; | |
return entryPoints.indexOf(a.names[0]) - entryPoints.indexOf(b.names[0]); | |
}, | |
inject: 'body', | |
minify: isProd | |
? { | |
caseSensitive: true, | |
collapseWhitespace: true, | |
keepClosingSlash: true | |
} | |
: false | |
}), | |
], | |
/** | |
* Disable performance hints | |
* See: https://github.com/a-tarasyuk/rr-boilerplate/blob/master/webpack/dev.config.babel.js#L41 | |
*/ | |
// performance: { | |
// hints: false | |
// }, | |
// devtool: 'inline-cheap-source-map' | |
}; | |
// 过滤一些默认的规则,使用自定义的 | |
commonConfig.module.rules = commonConfig.module.rules.filter(rule => { | |
if (rule.test) { | |
// 过滤 html 的解析 | |
if (rule.test.test('index.html') && rule.loader === 'raw-loader') { | |
return false; | |
} | |
// // 过滤 less 的解析 | |
if (rule.test.test('index.less')) { | |
return false; | |
} | |
} | |
return true; | |
}); | |
const mergedCfg = webpackMerge([commonConfig, customCfg]); | |
// console.log(cfgType, wco); | |
// console.log(mergedCfg.module.rules) | |
return mergedCfg; | |
}; |
如上内容示例,我们自定义了如下的 webpack 配置功能:
- 添加了
pug
模板编译支持; - 我们希望在模板内引用一些变量,使用了
HtmlWebpackPlugin
插件,并屏蔽了默认的 html 解析配置; - 我们使用 less 并希望实现
css sprites
,于是自定义了 less 的规则。
注意两点:
- 默认对
html
文件的解析 loader 必须屏蔽,否则模板会全部解析为字符串,ejs 语法不会生效; less-loader
当前不支持less 3.x
版本,应当安装less^2.7.x
。angular-cli 内部是采用postcss
实现的 less 编译。
4 在 package.json
配置 postinstall
钩子
在每次执行 npm install
或 yarn install
后,立即执行 node scripts/insert-to-cli-webpack.js
,即可实现自定义 webpack 配置的需求。
我们可以在 package.json
中配置执行注入脚本的命令 webpack.inject
,示例参考:
"scripts": { | |
"postinstall": "npm run webpack.inject", | |
"webpack.inject": "node scripts/insert-to-cli-webpack.js" | |
} |
正文完