开启子线程打包,加快打包速度,使用id标识css
rules: [
{
test:/\.css/,
use: 'Happypack/loader?id=css'
},
{
test: /\.js$/,
exclude:/node_modules/,
include:path.resolve(__dirname,'src'),
use: 'Happypack/loader?id=js'
}
]
// plugins
new HappyPack({
id:'css',
use:['style-loader','css-loader']
}),
new HappyPack({
id:'js',
use: [{
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-react' // react jsx
]
}
}]
}),
复制代码
当用 Webpack 去构建一个能够被其余模块导入使用的库时须要用到它们html
output.libraryTarget
配置以何种方式导出库output.library
配置导出库的名称 output.libraryTarget 是字符串的枚举类型,支持如下配置编写的库将经过var被赋值给经过library指定名称的变量。node
// bundle.js
var calculator=(function (modules) {}({})
// index.html
<script src="bundle.js"></script>
<script>
let ret = calculator.add(1,2);
console.log(ret);
</script>
复制代码
exports["calculator"] = (function (modules) {}({})
require('npm-name')['calculator'].add(1,2);
复制代码
module.exports = (function (modules) {}({})
require('npm-name').add();
复制代码
this["calculator"]= (function (modules) {}({})
this.calculator.add();
复制代码
window["calculator"]= (function (modules) {}({})
window.calculator.add();
复制代码
global["calculator"]= (function (modules) {}({})
global.calculator.add();
复制代码
把基础模块独立出来打包到单独的动态链接库里.react
const path=require('path');
const DllPlugin=require('webpack/lib/DllPlugin');
module.exports={
entry: {
react:['react','react-dom']
},// 把 React 相关模块的放到一个单独的动态连接库
output: {
path: path.resolve(__dirname,'dist'),// 输出的文件都放到 dist 目录下
filename: '[name].dll.js',//输出的动态连接库的文件名称,[name] 表明当前动态连接库的名称
library: '_dll_[name]',//存放动态连接库的全局变量名称,例如对应 react 来讲就是 _dll_react
},
plugins: [
new DllPlugin({
// 动态连接库的全局变量名称,须要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态连接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json')
})
]
}
复制代码
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
plugins: [
new DllReferencePlugin({
manifest:require('./dist/react.manifest.json')
})
]
复制代码
须要将dll文件先提早引入webpack
<script src="react.dll.js"></script>
<script src="bundle.js"></script>
复制代码
HTML文件不缓存,放在本身的服务器上,关闭本身服务器的缓存,静态资源的URL变成指向CDN服务器的地址web
静态的JavaScript、CSS、图片等文件开启CDN和缓存,而且文件名带上HASH值npm
为了并行加载不阻塞,把不一样的静态资源分配到不一样的CDN服务器上json
接入cdn(publicPath)promise
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name]_[hash:8].js',
publicPath: 'http://img.zhufengpeixun.cn'
},
复制代码
Tree Shaking 能够用来剔除JavaScript中用不上的死代码。它依赖静态的ES6模块化语法,例如经过import和export导入导出。缓存
use:[{
loader: 'babel-loader',
options: {
presets:[['@babel/preset-env',{modules: false }],'@babel/preset-react']
}
}]
复制代码
npx webpack --display-used-exports
复制代码
webpack --display-used-exports --optimize-minimize
复制代码
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,//启动缓存
parallel: true,//启动并行压缩
//若是为true的话,能够得到sourcemap
sourceMap: true // set to true if you want JS source maps
}),
//压缩css资源的
new OptimizeCSSAssetsPlugin({})
]
}
复制代码
大网站有多个页面,每一个页面因为采用相同技术栈和样式代码,会包含不少公共代码,若是都包含进来会有问题
optimization: {
splitChunks: {
cacheGroups: {
commons: { // 页面之间的公共代码
chunks: "initial",
minChunks: 2,//最小重复的次数
minSize: 0//最小提取字节数
},
vendor: { // 第三方库
test: /node_modules/,
chunks: "initial", // 先抽离公共的第三方库
name: "vendor",
}
}
}
}
复制代码
Scope Hoisting 可让 Webpack 打包出来的代码文件更小、运行的更快, 它又译做 "做用域提高",是在 Webpack3 中新推出的功能。
// hello.js
export default 'Hello';
// index.js
import str from './hello.js';
console.log(str);
// main.js
var n = name = "Hello";
console.log(n)
复制代码
用户当前须要用什么功能就只加载这个功能对应的代码,也就是所谓的按需加载 在给单页应用作按需加载优化时,通常采用如下原则:
// handler.js
module.exports=function () {
alert('你点我啦!');
}
// index.js
document.querySelector('#clickBtn').addEventListener('mouseover',() => {
import('./handler').then(clickMe => {
window.clickMe=clickMe.default;
});
});
// html
<div id="clickBtn" onclick="clickMe()">弹框</div>
复制代码
react-router4 路由懒加载
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {HashRouter as Router,Route} from 'react-router-dom';
import Bundle from './Bundle';
let LazyAbout=(props) => (<Bundle {...props} load={()=>import('./About')}/>)
let Home=() => <div>Home</div>
ReactDOM.render(
<Router>
<div>
<Route path="/" component={Home} />
<Route path="/about" component={LazyAbout}/>
</div>
</Router>,document.getElementById('root'));
// Bundle
import React from 'react';
export default class Bundle extends React.Component{
state={Mod: null}
componentWillMount() {
this.props.load().then(mod=>this.setState({Mod: mod.default? mod.default:mod}));
}
render() {
let Mod=this.state.Mod;
return Mod&&<Mod {...this.props}/>;
}
}
// about
import React from 'react';
export default props => <div>About</div>
复制代码
const webpack = require('webpack');
module.exports = {
entry:{
main:'./src/index.js',
},
plugins: [
// 该插件的做用就是实现模块热替换,实际上当启动时带上 `--hot` 参数,会注入该插件,生成 .hot-update.json 文件。
new webpack.NamedModulesPlugin(), // 用于启动 HMR 时能够显示模块的相对路径
new webpack.HotModuleReplacementPlugin(), // Hot Module Replacement 的插件
],
devServer:{
// 告诉 DevServer 要开启模块热替换模式
hot: true,
}
};
复制代码
import React from 'react';
import { render } from 'react-dom';
import App from './App';
import './index.css';
render(<App/>, document.getElementById('root'));
// 只有当开启了模块热替换时 module.hot 才存在
if (module.hot) {
// accept 函数的第一个参数指出当前文件接受哪些子模块的替换,这里表示只接受 ./AppComponent 这个子模块
// 第2个参数用于在新的子模块加载完毕后须要执行的逻辑
module.hot.accept(['./App'], () => {
// 新的 AppComponent 加载成功后从新执行下组建渲染逻辑
let App=require('./App').default;
render(<App/>, document.getElementById('root'));
});
}
复制代码