打包库和组件
题目:实现一个大整数加法库的打包,要求:1.需要打包压缩版和非压缩版;2.支持AMD/CJS/EMS模块引入,也可以通过script标签形式引入
| 支持模式 | 引入语法 |
|---|---|
| ES module | import * as largeNumber from 'large-number'; largeNumber.add('999','1'); |
| 支持CJS | const largeNumbers = require('large-number'); largeNumber.add('999','1'); |
| 支持AMD | require(['larger-bunber'],function(larger-bunber){ largeNumber.add('999','1'); }); |
| 支持script | <script src="https://xxx/large-number"></script><script largeNumber.add('999','1');//global variablewindow.largeNumber.add('999','1');//挂在window上 |
实现步骤
1.webpack文件配置,其中包含库打包的入口,出口,对外暴露的名字等
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
entry: {
'large-number': './src/index.js',
'large-number.min': './src/index.js'
},
output: {
filename: '[name].js',
// library为库暴露出去的名称
library: 'largeNumber',
// 导出结果的形式
libraryTarget: 'umd',
//这里需要声明,不然调用地方需要 再.default才能访问
libraryExport: 'default'
},
mode: 'none',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
// UglifyJS 在 ES6 代码压缩上做的不够好,代码也不再维护,terser是UglifyJS的分支,一直有维护。
include: /\.min\.js$/
})
]
}
}
2.配置不同环境的入口-跟目录下的index
// package.json的main字段为index.js
if (process.env.NODE_ENV === 'production') {
module.exports = require('./dist/large-number.min.js');
} else {
module.exports = require('./dist/large-number.js');
}
3.各种libraryTarget配置详细解读
juejin.cn/post/700434…
webpack5用法:tehub.com/a/9KvNfaKdt…
实现ssr打包
实现步骤
1.创建服务端的编译文件webpack.ssr.js
// 1.output需要增加libraryTarget
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]-server.js',
// SSR的时候Node.js需要去require我们生成的这个js文件,而Node.js的包管理遵从commonjs规范,因此构建生成的这个js文件需要兼容commonjs。
// 否则无法再 Node.js 里面进行 require。
libraryTarget: 'umd'
},
// 2.HtmlWebpackPlugin入口文件需要修改一下
2.package.json中增加启动命令
"build:ssr": "webpack --config webpack.ssr.js"
3.创建server目录,目录下创建index.js,作为服务端的编译文件
// 增加一个hack
if(typeof window === 'undefined') {
global.window = {};
}
const fs = require('fs');
const path = require('path');
const express = require('express');
// react组件转字符串
const {renderToString} = require('react-dom/server');
// 需要渲染的组件
const SSR = require('../dist/search-server');
const template = fs.readFileSync(path.join(__dirname, '../dist/search.html'), 'utf-8');
const data = require('./data.json');
const server = port => {
const app = express();
app.use(express.static('dist'));
app.get('/search', (req, res) => {
const html = renderMarkup(renderToString(SSR));
res.status(200).send(html);
});
app.listen(port, () => {
console.log('running at' + port)
});
}
server(process.env.PORT || 3000);
const renderMarkup = str => {
const dataStr = JSON.stringify(data)
return template.replace('<!--HTML_PLACEHOLDER-->', str)
.replace('<!--INITIAL_DATA_PLACEHOLDER-->', `<script>window.__initial_data=${dataStr}</script>`)
}
// 该当时解决样式问题比较曲折
// // 返回一个html页面,用一个模版字符串包装一下
// const renderMarkup = str => {
// return `<!DOCTYPE html>
// <html lang="en">
// <head>
// <meta charset="UTF-8">
// <meta name="viewport" content="width=device-width, initial-scale=1.0">
// <meta http-equiv="X-UA-Compatible" content="ie=edge">
// <title>Document</title>
// </head>
// <body>
// <div id="root">${str}</div>
// </body>
// </html>`;
// }
4.增加服务端入口文件search/index-server.js
'use strict';
// 因为是服务端,所以需要commonjs
const React = require('react');
const logo = require('./images/logo.png');
require('./search.less');
class Search extends React.Component {
constructor() {
super(...arguments);
this.state = {
Text: null
}
}
render() {
const {Text} = this.state;
return <div className="search-text">
搜索文字的a<img src={ logo } onClick={this.loadComponent.bind(this)}/>
</div>;
}
}
// server不能使用reactDOM.render进行渲染
module.exports = <Search />;
5.html中加入占位符用于替换:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="root"><!--HTML_PLACEHOLDER--></div>
<!--INITIAL_DATA_PLACEHOLDER-->
</body>
</html>
优化构建日志
// 1.配置stats,生产环境配置直接配置在module中,dev环境配置在devServer中
stats: 'errors-only'
// 2.安装插件:friendly-errors-webpack-plugin,放在plugins中
plugins: [
new FriendlyErrorsWebpackPlugin()
]
构建异常和中断处理
plugins: [
function() {
this.hooks.done.tap('done', stats => {
if (stats.compilation.errors
&& stats.compilation.errors.length
&& process.argv.indexOf('--watch') == -1
) {
// 添加错误日志
console.log('build error')
// 更改错误码
process.exit(1);
}
})
}
]
实际未生效。。。待排查