对于之前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 tree
import 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
代码生效。