ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## FAQ ### webpack4.x有哪些默认行为? 默认入口为`./src/index.js` 默认出口为`./dit` 默认`mode`为`production`,打包出的js文件会被压缩 ### 如何改变打包模式? 默认为`production`, 我们可以在package.json中通过给脚本添加`--development`运行,转换成`development`模式 ``` "scripts": { "dev":webpack --development ... ``` 也可以在配置文件中 ``` entry:... ... , mode: 'development' ... ``` ### entry有几种写法? >[danger] **注意:** 路径必须带上`./` 字符串的形式:单进单出 ``` entry:'./src/index.js' ``` 数组的形式:支持多进单出 ``` entry: ['./src/a.js','./src/b.js'] ``` 对象的形式:支持多进多出 ```javascript entry:{ a:'./src/a.js' ,b:'./src/b.js' } ``` ### 如何控制打包出的文件的名字和路径? ``` ,output: { filename: "./test/[name].js" ,path:path.resolve(__dirname,'dist') } ``` 我们可以通过配置output对象中的`path`来决定我们打包后输出文件的**根路径**。(注意这个path路径一定是**绝对路径**) 之所以说是根路径,是因为我们能通过配置output对象中的`filename`来近一步控制我们的输出路径。 除此之外filename也决定了我们输出文件的名字,我们还能通过在filenmae中使用`[name]`关键字来动态生成输出文件的名字,动态生成的文件名和我们在entry对象中设置的名字一样,如果entry不是个对象,那么此时输出的文件名会默认为main。 ### 如何控制html引入哪些打包后的资源? 默认`html-webpack-plugin`会引入所有打包出的资源。 但我们也可以使用HtmlWebpackPlugin中的`chunks`参数来控制我们每个html模板中想要引入的资源 ``` ,new HtmlWebpackPlugin({ template:'./src/index.html' ,filename:'index.html' ,chunks:['index'] }) ,new HtmlWebpackPlugin({ template:'./src/index.html' ,filename:'a.html' ,chunks:['a','index'] }) ``` 其中new了几个就会输出几个html,另外`filename`指定的是要输出的html的文件名。 ### 如何将css和less分开打包? 创建两个实例 ``` let cssExtract = new ExtractTextWebpackPlugin('css.css'); let lessExtract = new ExtractTextWebpackPlugin('less.css'); ``` 注册 ``` ,plugins:[ ... ,cssExtract ,lessExtract ... ``` 配置 ``` {test:/\.css$/,use:cssExtract.extract({ fallback: 'style-loader' ,use:['css-loader'] })} ,{test:/\.less$/,use:lessExtract.extract({ fallback: 'style-loader' ,use:['css-loader','less-loader'] })} ``` ### 如何设置developmen或production的环境变量?如何在配置和项目文件中获取? ``` npm i cross-env -D ``` ``` "scripts": { "build": "cross-env NODE_ENV=production webpack", "start": "cross-env NODE_ENV=development webpack-dev-server", ... ``` 这样我们就能来在配置文件中获取到是`development`还是 `production` ``` // webpack.config.js let isDev = process.env.NODE_ENV === 'development'; //一顿配置操作。。。噼里啪啦,不对,是ctl+v ``` 除了在配置文件中,我们也能在项目文件中拿到这环境变量 ``` //使用这个插件注入一个全局的变量 ... let webpack = require('webpack'); ... , new webpack.DefinePlugin({ __DEV__: isDev }) ``` ### 我的css为什么不会更新了? 出现这种情况很有可能是你用了`extract-text-webpack-plugin`,这个插件抽离出去的css文件并不支持webpack-dev-server的更新。 So,我们一般在开发的时候使用`style-loader`。 你可以根据设置的环境变量来切换使用哪种css的插入模式。 ``` //实例化和注册plugin时 , new ExtractTextWebpackPlugin({ filename: 'css/index.css' ,disable:isDev // 依据环境变量来决定是否启用该插件 }) ``` ``` , use: ExtractTextWebpackPlugin.extract({ fallback: 'style-loader ... ``` ### 引入路径太长,想要简化?想要省略后缀?想要自定义模块查询? ``` , resolve: { alias: { 'bootstrap': path.resolve(__dirname, 'node_modules/bootstrap/dist/css/bootstrap.css') } , extensions: [' ', '.js', '.json', '.css'] //第一个放空 规定 , modules: ['node_modules', 'lib'] // , mainFields: [] //默认package.json的main是文件的入口 这里可以自定义 } ``` ## 功能 ### 添加html模板自动插入打包文件 ``` npm i html-webpack-plugin -D ``` ``` ,new HtmlWebpackPlugin({ template:'./src/index.html' //用哪个html作为模板 ,hash:true ,minify:{ //压缩html collapseWhitespace:true //去除空白 ,removeAttributeQuotes:true //去除引号 } }) ``` >hash: 设置为true时,能有效防止开发时重新打包后依然引入服务器过去缓存的资源, 打包后的文件的引入路径是这样的 ``` src="bundle.js?2baa6d527087b9fdd38d" ``` ### 启用一个自动刷新服务器 ``` npm i webpack-dev-server -D ``` ``` ,devServer:{ contentBase:'dist' //可以在url栏中输入对应地址访问到dist目录下的静态资源 ,host:'localhost' ,port:3000 ,open:true // 自动弹出浏览器 ,hot:true // 必须搭配热替换插件 webpack自带 } ``` ### 打包前自动清理输出目录 ``` let CleanWebpackPlugin = require('clean-webpack-plugin'); ``` ``` new CleanWebpackPlugin(['dist']) //['dist/a','dist/b'] ``` 之所以参数接收的是一个数组,就是因为它支持选择性清空输出目录下文件。 ### 处理css资源 ``` npm i style-loader css-loader -D ``` 将css样式插入到style标签中 ``` {test:/\.css$/,use:['style-loader','css-loader']} ``` 抽离到css文件并自动使用link引入 ``` npm i extract-text-webpack-plugin@next -D ``` ``` {test:/\.css$/,use:ExtractTextWebpackPlugin.extract({ fallback: 'style-loader' ,use:['css-loader'] })} ``` ### 处理less/sass资源 ``` npm i node-sass sass-loader less less-loader -D ``` ``` ,{test:/\.less$/,use:lessExtract.extract({ fallback: 'style-loader' ,use:['css-loader','less-loader'] })} ,{test:/\.(sass|scss)/,use:ExtractTextWebpackPlugin.extract({ fallback: 'style-loader' ,use:['css-loader','sass-loader'] })} ``` ### 拷贝指定文件到输出目录的指定位置 一般来说是些README撒的 ``` let CopyWebpackPlugin = require('copy-webpack-plugin'); ... , new CopyWebpackPlugin([{ from: './src' , to: 'public' }]) ``` ### postcss ``` npm i postcss-loader autoprefixer -D ``` ``` {test:/\.css$/,use:ExtractTextWebpackPlugin.extract({ use:['css-loader','postcss-loader'] })} ``` 再创建一个`postcss.config.js`文件,注册你想要的postcss的功能 ``` //postcss.config.js module.exports = { plugins:[require('autoprefixer')] } ``` ### es6+、react等转译 ``` npm i babel-core babel-loader babel-preset-env babel-preset-react babel-preset-stage-0 -D ``` ``` , { test: /\.jsx?$/ , use: [ { loader: 'babel-loader' , options: { presets: ['env', 'stage-0', 'react'] //顺序不能乱 } }] , exclude: /node_modules/ , include: /src/ } ``` 你也可以选择单独在`.babelrc`中配置你的babel `options` ``` { "presets":["env","stage-0","react"] } ``` ### 处理图片资源 ``` npm i file-loader url-loader -D ``` ``` , { test: /\.(png|gif|jpg|jpeg)$/ , use: [ { loader: 'url-loader' , options: { limit: 5 //低于5字节图片将以base64的形式存在 , outputPath: 'images/' } }] , exclude: /node_modules/ , include: /src/ } ``` 图片引用的三种形式 - 在js中引用图片 ``` let oImg = new Image(); import png from './1.png'; //如果引入了图片 就可以把图片进行打包,其中png不是图片本身,而是文件的路径 oImg.src = png; //如果不是用import引入的将不会被打包 document.body.appendChild(oImg); ``` - 在背景图中使用 ``` background:url('1.png'); //开发目录中图片相对css文件的路径 ``` - 直接通过路径引用 相对 html 需要额外的包 ``` npm i html-withimg-loader -D ``` ``` <img src="./eg4/1.png" alt=""> //图片相对于html模板的路径 ``` ### hotmodule PurifyWebpack ## optimization ### 打包速度优化 #### exclude和include ``` , exclude: /node_modules/ , include: /src/ ``` #### dll动态链接库 一个项目中的第三方包我们大多数情况下是不需要修改的,So当项目中我们自己文件的更改导致整个项目重新打包是很消耗性能的,比如,第三方库我们完全不需要再重新打包。 So,DllPlugin就是为了解决这个问题,它会将我们的第三方库生成为动态链接库,这样当项目更新重新打包时候就不再需要打包第三方库的部分,只需要引用这个动态链接库即可。 首先,单独打包一份项目中要使用的第三方库 ``` let path = require('path'); let webpack = require('webpack'); module.exports = { entry:{ vendor:['react','react-dom'] } , mode: 'development' , output: { filename: '[name].js' , path: path.join(__dirname, 'dist') , library: '_dll_[name]' //必须和DllPlugin中设置的name一样 } , plugins: [ new webpack.DllPlugin({ name:'_dll_[name]' //打包后的文件名 ,path:path.resolve(__dirname,'dist','[name].manifest.json') //必须是json //打到哪去 }) ] } ``` 最终会在`dist`目录下生成两个文件`vendor.js`和`vendor.manifest.json`。 这个时候需要我们在`index.html`中手动引入`vendor.js` ``` <script src="./vendor.js"></script> //打包后html和vendor是平级的,故这里为./vendor.js ``` 然后,我们还需要在我们项目打包时引入`vendor.manifest.json` ``` ,new webpack.DllReferencePlugin({ manifest:path.join(__dirname,'dist','vendor.manifest.json') }) ``` ### 线上加载优化 #### splitChunks代码分隔 ``` ,optimization:{ splitChunks:{ cacheGroups:{ vendor:{ test:/node_modules/ //引node_modules中的才会抽离到vendor ,chunks:'initial' ,name:'vendor' ,priority:10 //提高优先级,会先抽离vendor } ,commons:{ //commons优先级默认比vendor高 chunks:'initial' ,name:'commons' ,minSize:0 //只要超出0字节就生产新的包 } } } } ```