几种基本用法
清理构建的目录
可以通过在执行构建的命令前加一句清除目录的命令
如在package.json里面的build命令修改为
"scripts": {
build: rm -rf ./dist && webpack
}
比较常用的是通过webpack的插件实现
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
modules.export = {
plugins: [
new CleanWebpackPlugin()
]
}
处理样式
我们需要添加css前缀来处理兼容性问题。通过配置postcss-loader来实现。注意是先添加前缀然后再把scss转换成css,所以要写在最下面。
{
test: /.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
})
]
}
}
]
},
modules.export = {
plugins: [
new OptimizeCssAssetsWebpackPlugin({
assetNameRegExp: /\.css$/g,
cssProcessor: require('cssnano')
})
]
}
对于字体大小的兼容,我们可以使用rem作为字体的单位。但是把px转换成rem是一个比较麻烦的计算过程,而且需要对不同分辨率下的设备,设置不同的根元素字体大小,从而调整整体的字体大小。一个解决方案就是,在html页面引入flexible.js,再样式文件的loader里面添加px2rem-loader。
引入flexible.js,可以通过直接用script标签引入cdn的链接,也可以通过文件内联的形式,也就是把flexible.js里面的内容,直接嵌入到<script></script>中。这里只介绍内联方式。
由于我们使用的是html-webpack-plugin把html模板编译到dist下面,所以是支持ejs语法。需要babel-loader把文件的内容转换成兼容性好的代码,然后用raw-loader把文件内容输出成字符串。注意这里的raw-loader安装的是0.5版本。
<script>
${require('raw-loader!babel-loader!../../../node_modules/lib-flexible/flexible.js')}
</script>
这样我们打包出来的文件就是
<script>
flexible.js的内容
</script>
添加px2rem-loader
{
test: /.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'px2rem-loader',
options: {
remUnit: 75, // 1px=75rem
remPrecision: 8 // 计算rem保留的精度
}
},
'sass-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
require('autoprefixer')({
overrideBrowserslist: ['last 2 version', '>1%', 'ios 7']
})
]
}
}
]
}
提取公共资源
多页应用通用打包方案
这里主要是通过动态获取要打包的page路径,生成entry和对应的html-webpack-plugin
const setMAP = () => {
const entry = {};
const htmlWebpackPlugins = [];
const entryFiles = glob.sync(path.join(__dirname, './src/pages/*/index.js'));
Object.keys(entryFiles).forEach((index) => {
const entryFile = entryFiles[index]
const match = entryFile.match(/src\/pages\/(.*)\/index\.js/);
const pageName = match && match[1];
entry[pageName] = `./src/pages/${pageName}/index.js`
console.log(pageName)
htmlWebpackPlugins.push(new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/pages/${pageName}/${pageName}.html`),
filename: `${pageName}.html`,
chunks: [pageName],
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
}))
})
return {
entry,
htmlWebpackPlugins
}
}
const { entry, htmlWebpackPlugins } = setMAP()
modules.export = {
entry,
plugins: [
].concat(htmlWebpackPlugins)
}
基础库分离
一种方案是通过html-webpack-externals-plugin,然后在html里面直接引入组件库的cdn链接
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
moudles.export = {
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: '//11.url.cn/now/lib/16.2.0/react.min.js',
global: 'React'
},
{
module: 'react-dom',
entry: '//11.url.cn/now/lib/16.2.0/react-dom.min.js',
global: 'ReactDom'
}
]
})
]
}
html
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script>
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script>
另外一种方法是通过webpack4的
SplitChunksPlugins实现,顺便提一下,webpack3使用的是commonChunksPlugin
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/pages/search/search.html`),
filename: `search.html`,
chunks: ['vendors', 'common', 'search'], //注意这里要引入vendors跟common
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
})
]
optimization: {
splitChunks: {
minSize: 0,
cacheGroups: {
vendors: {
test: /(react|react-dom)/,
name: 'vendors',
chunks: 'all',
priority: -10 // 需要设置权重才能都分离出来
},
common: {
name: 'commons',
chunks: 'all',
minChunks: 2,
priority: -20
}
}
}
},
}
代码动态分割和import
ES6还不支持这个功能,需要借助babel插件实现。
npm install @babel/plugin-syntax-dynamic-import --save-dev
在babel的配置文件.babelrc里面添加
{
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}
使用的时候直接通过import函数引入某个组件
loadComponent () {
import("./text.js").then((Text) => {
console.log(Text)
this.setState({
Text: Text.default // 注意这里设置的是Text.default
})
})
}
这样就可以发现,text.js被打包成一个独立的js,当触发loadComponent在浏览器的network里面才看到这个文件。
优化显示日志
我们在build的时候,可能只需要看到报错的日志,可以通过设置stats来控制要显示的日志。同时配合插件friendly-errors-webpack-plugin优化日志的输出。
stats参数:
modules.export {
plugins: [
new FriendlyErrorsWebpackPlugin()
],
stats: 'errors-only'
}
打包组件跟库
react ssr简单demo
几个重要的概念
socucemap
tree shaking
概念:就是在构建的过程中,删除掉我们不需要用的代码。<br/>
优化原则:无用代码的判断,是根据DCE原则,某些代码不会被执行,或者是执行后的结果不会被用到,或者是执行的结果被用到的变量并没有被使用,这些代码都是无效代码,在tree-shaking中要被优化掉的。<br/>
执行阶段:这里是通过静态分析,在编译阶段实现的<br/>
特点:使用ES6的import方法引入文件是可以进行tree-shaking,require是动态引入的文件,无法进行tree shaking, 因为不会在运行的时候还去分析优化代码。<br/>
如何开启:webpack4的production模式是默认会开启tree-shaking的
scope hoisting
webpack在编译的时候,会把import进来的模块用闭包函数包裹,然后通过__webpack_require__的形式使用。这样会导致两个问题。<br/>
1、打包的代码体积比较大。<br/>
2、运行时的内存开销比较大。<br/>
scope hoisting通过把import进来的模块,直接内联到同一个闭包函数中,通过替换变量名的方式,避免代码冲突,来减少代码里面的闭包函数。但是需要注意的是仅仅对只被引入过一次的函数使用这个方案,对多次被引入的,我们还是希望它是一个独立的闭包模块,便于多次使用。
特点:仅在ES6的import下生效,动态引入的require模式下不起作用。<br/>
如何开启:webpack4的production模式是默认会开启tree-shaking的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。