对于之前webpack使用与配置(上)
的补充
使用
typescript时需要在根目录下创建一个tsconfig.js的文件-
关于
.babelrc的配置- 直接在
webpack.config.js中配置options - 创建
.babelrc文件,在该文件中配置 - 注意二者取其一就行了,当然也可以两者互补,只要两者合并起来能满足配置需求即可
在
webpack.config.js中的配置是这样的:{ test: /\.js$/, // normal 普通的 loader use: { loader: 'babel-loader', options: { // 用babel-loader 需要把 es6 -> es5 presets: [ '@babel/preset-env', '@babel/preset-react' ], plugins: [ ["@babel/plugin-proposal-decorators", { "legacy": true }], // 装饰器语法 ["@babel/plugin-proposal-class-properties", { "loose": true }], // 支持 class 语法 "@babel/plugin-transform-runtime", // 运行时,支持 promise 或 gen* "@babel/plugin-syntax-dynamic-import", // 支持 import then 语法 ] } }, include: path.resolve(__dirname, '../src'), // 指定为 src 文件 exclude: /node_modules/, // 排除 node_modules }在
.babelrc中的配置是这样的:{ presets: [ '@babel/preset-env', '@babel/preset-react' // 使用react必须配置的presets项 ], plugins: [ ["@babel/plugin-proposal-decorators", { "legacy": true }], // 装饰器语法 ["@babel/plugin-proposal-class-properties", { "loose": true }], // 支持 class 语法 "@babel/plugin-transform-runtime", // 运行时,支持 promise 或 gen* "@babel/plugin-syntax-dynamic-import", // 支持 import then 语法 ] }终于可以摆脱脚手架了。。。。。*(幼稚的想法)
- 直接在
-
hash、chunkhash和contenthash的配置-
hash计算是跟整个项目的构建相关,也就是说如果配置的是hash,那么只要项目中一个文件发生变化,那么所有的hash都会发生变化,这对缓存来说是一种浪费,使用hash时所有的hash值都是一样的,发生变化时一起变化 -
chunkhash就是解决上面这个问题的,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。即一个chunk里面修改的内容不会影响到另一个chunk,只有自己这个chunk的chunkhash会发生变化- 我们更近一步,
index.js和index.css同为一个chunk(index.css是同一个chunk里面抽出来的),如果index.js内容发生变化,但是index.css没有变化,打包后他们的hash都发生变化,这对css文件来说是一种浪费。如何解决这个问题呢?contenthash将根据资源内容创建出唯一hash,也就是说文件内容不变,hash 就不变。
- 我们更近一步,
-
-
mini-css-extract-plugin的使用姿势:- 先是装包,在
plugins里面new出来一个实例
new MiniCssExtractPlugin({ filename: 'index.[contenthash:8].css' // 使用contenthash的好处见上一条 }),- 修改
rules里面的配置,现在不是用style-loader了,而是要利用mini-css-extract-plugin提供的loader
{ test: /\.scss$/, use: [ // 这里替换了原来的style-loader { loader: MiniCssExtractPlugin.loader, options: { hmr: true, reloadAll: true } }, { loader: 'css-loader', options: { modules: true } }, 'sass-loader', 'postcss-loader'], }如果不抽离
css文件那么所有的css样式内容都会在打包后被放在bundle.js文件中,造成的结果就是bundle.js文件内容过大,如果是一个单页应用的话,需要花更多的时间去下载bundle.js,首屏体验就不好,抽离css文件的作用应该就是这个,将css样式的内容抽离出css文件,通过link标签引入index.html中,这样在下载css内容的时候可以继续构建DOM树也可以继续下载后面的bundle.js,阻塞的只是DOM的渲染和bundle.js的执行,总体来说是提升了性能的。 - 先是装包,在
-
optimize-css-assets-webpack-plugin
这个插件用于对css资源进行压缩,食用方式是在optimization里面进行配置const OptimizeCss = require('optimize-css-assets-webpack-plugin') const Uglify = require('uglifyjs-webpack-plugin') mode: 'production', optimization: { minimizer: [ new OptimizeCss(), new Uglify(), ], },注意:虽然
mode已经设置为production,但是使用了optimize-css-assets-webpack-plugin插件之后如果不使用uglifyjs插件的话js文件将无法压缩,展现出来的是和development模式是一样的,当然如果设置的是development模式的话,即使使用了uglifyjs插件也无法压缩。 -
externals配置
譬如通过<script></script>标签引入了jQuery的CDN,此时在文件中使用$或者window.$都可以直接使用jQuery,也不需打包进bundle.js,但是如果此时又写了import $ from 'jquery'(纯属为了看着顺眼);的话,jQuery又会被打包进bundle.js,为了避免这样的情况(不用引入的情况偏偏引入了,又不想打包),可以通过配置externals属性来忽略一些不需要打包的内容externals: { jquery: '$', } -
在处理图片时,有三种情况
- 在
js文件中创建img,然后添加进DOM treeimport imgSrc from './a.jpg'; const image = new Image() image.src = imgSrc - 在
css文件中作为background使用{ backgroung: url('./a.jpg'); // 此时不需要先引入,是因为css-loader已经做了这一步操作 } - 在
html文件中直接使用
为了将该<img src='./a.jpg' />src转化为图片打包后的地址,使用一个loader:html-withimg-loader{ test: /\.html$/, loader: 'html-withimg-loader' }
注意:在配置
webpack.config.js时可以像下面这样配置,但是虽然我们只使用了url-loader,但是需要同时装包file-loader,因为由于limit的限制,当图片文件大于200K时会使用file-loader打包出一个图片文件放在build文件夹下,图片大小小于limit限制时是以base64的形式打包进bundle.js文件,也就是说url-loader里面可能会使用到file-loader,这样做的目的也是为了防止bundle.js文件过大,另一个原因是图片过大时编码需要的时间较长,影响打包的速度。但是如果图片较多,会发很多http请求,会降低页面性能,所以当图片体积较小时url-loader会将引入的图片编码,转为base64字符串。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了,节省了图片请求。``` { test: /\.(jpg|png|gif)$/, use: { loader: 'url-loader', options: { limit: 200*1024, outputPath: 'img/' // 会在build目录下创建一个img目录 } } }, ``` - 在
关于
publicPath的配置,这是代码上线后将资源托管在CDN服务器上,此时html文件中引入各个bundle.js文件不再是本地引入,而是要去CDN服务器上引入,如果继续写成./bundle.js就无法获取到资源,所以就要给所有的引入路径添加上一个公共的路径,譬如说放在http://www.navyblue.com/的CDN服务器上,那么publicPath就设置为http://www.navyblue.com/,这时候在html引入bundle.js的时候就会自动去引入http://www.navyblue.com/bundle.js。如果在output中配置publicPath那么打包出来的所有结果被引入时都会加上公共路径,如果想单独配置,譬如说只给图片加,那么就可以在url-loader的options里面配置
{ test: /\.(jpg|png|gif)$/, use: { loader: 'url-loader', options: { limit: 200*1024, outputPath: 'img/', // 会在build目录下创建一个img目录 publicPath: 'http://www.navyblue.com/' } } },-
关于
chunk、bundle、module的区别:-
module好理解,就是需要被打包的一个个模块 -
bundle就是打包出来的一个个js文件 -
chunk:一个entrypoint进去以后,根据各种依赖关系形成一大个chunk,如果在打包一个chunk的过程中需要分割代码,那么分割完最后得到的一个个包就是bundle。
-
-
关于
html-webpack-plugin的使用: 对于多页应用需要new多个plugin出来new HtmlWebpackPlugin({ template: './src/index.html', minify: { removeAttributeQuotes: true, }, filename: 'home.html', // filename是打包结束后输出的html文件名 chunks: ['main'], // chunks是指该html需要引入的js文件,里面的`main`其实就是一个entrypoint,因为一个entrypoint对应的就是一个chunk }), new HtmlWebpackPlugin({ template: './src/index.html', minify: { removeAttributeQuotes: true, }, filename: 'other.html', chunks: ['sub'], }), -
resolve的配置:resolve: { // 解析模块的可选项 modules: [ // 模块的查找目录 "node_modules", path.resolve(__dirname, "app") ], extensions: [".js", ".json", ".jsx", ".css"], // 用到的文件的扩展 alias: { // 模块别名列表 "module": "new-module" // 用到的别名:真正的路径 }, }, production mode(生产模式) 可以开箱即用地进行各种优化。 包括压缩,作用域提升,tree-shaking等。-
对于
cacheGroups的配置:splitChunks: { chunks: 'all', minSize: 50000, minChunks: 2, // 内部的minChunks可以覆盖这里的minChunks cacheGroups: { lodash: { name: 'mylodash', test: /[\\/]node_modules[\\/]lodash/, // 选择匹配的模块 // 譬如第一个包打包的只有lodash,因为没匹配到react所以不会分割到这个包里 minChunks: 1, priority: 10, // 打包会根据priority的大小从大到小打包 }, react: { name: 'myreact', test: /[\\/]node_modules[\\/]react/, minChunks: 1, priority: 5, }, vendors: { name: 'myGroups', test: /[\\/]node_modules1[\\/]/, priority: -10, minChunks: 1, }, default: { name: 'default', // 默认有个default配置,但是如果显示写出来又全都没匹配中的话会再次调用一个隐式的default minChunks: 1, priority: -20, } } }, @babel/polyfill
Babel默认只转换新的JavaScript句法(syntax),而不转换新的API,比如Iterator、Generator、Set、Map、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码。
举例来说,ES6在Array对象上新增了Array.from方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用@babel-polyfill,为当前环境提供一个垫片,使得在当前环境下可以执行该方法。
- 关于
CSS代码
css-loader:负责解析 CSS 代码,主要是为了处理 CSS 中的依赖,例如 @import 和 url() 等引用外部文件的声明
style-loader 会将 css-loader 解析的结果转变成 JS 代码,运行时动态插入 style 标签来让 CSS 代码生效。