# webpack-todo **Repository Path**: lu_shilei/webpack-todo ## Basic Information - **Project Name**: webpack-todo - **Description**: No description available - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-03-09 - **Last Updated**: 2021-11-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # webpack2配置实战 ## 一 处理CSS ### 解析CSS #### 1.css-loader ​ 解析css文件 #### 2.style-loader ​ 将解析的css已link标签的方式载入html文件 #### 3.stylus-loader(以stylus为栗子) ​ 处理stylus的css预处理文件 #### 4.postcss-loader + autoprefixer ​ 兼容各种浏览器,添加前缀 ​ `注意:1.需要在项目根目录下新建 postcss.config.js文件.2.在package.json 文件里配置` ​ ```js // postcss.config.js module.exports = { plugins: { require('autoprefixer') } } ``` ​ ```json // package.json { ... "browserslist": { "last 2 versions", "> 1%", "iOS 7", "last 3 iOS versions" } } ``` ​ ### 单独提取CSS文件 ​ 1.extract-text-webpack-plugin ```js const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'); module.exports = { moduld: { rules: [ { test: /\.css$/, use: { ExtractTextWebpackPlugin.extract({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader'], publicPath: '../../', //处理css里面的url }) } }, { test: /\.styl$/, ExtractTextWebpackPlugin.extrat({ fallback: 'style-loader', use: ['css-loader', 'postcss-loader', 'stylus-loader'], publicPath: '../../', //处理css里面的url }) } ] }, plugins: [ new ExtractTextPlugin({ filename; path.posix.join('static', 'css/[name].css'), allChunks: true }) ] } ``` ​ ### 压缩CSS #### 1.optimize-css-assets-webpack-plugin ​ 压缩CSS,去除文件空格 ### 对CSS开启gzip压缩 #### 1.compression-webpack-plugin ​ ```js const CompressionWebpackPlugin = require('compression-webpack-plugin'); const optimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') const gzipType = ['js', 'css', 'png'] module.exports = { plugins: [ new optimizeCssAssetsWebpackPlugin({ cssProcessorOptions: { safe: true, }, }), new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: new Regexp("\\.("+ gzipType.join('|') +")$"), threshold: 100, minRatio: 0.8, }) ] } ``` ​ ​ ## 二 处理JS ​ 1.解析JS #### 1.babel-loader + bable-core(核心) ​ 将ES6语法解析为浏览器能识别的语法 #### 2`.babel-polyfill` 或者 `babel-runtime` > **babel-polyfill**: Babel默认只转换新的JavaScript语法(syntax),如箭头函数等,而不转换新的API,比如Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise等全局对象,以及一些定义在全局对象上的方法(比如Object.assign)都不会转码;因此我们需要polyfill。它是通过向全局对象和内置对象的prototype上添加方法来实现的。比如运行环境中不支持Array.prototype.find 方法,引入polyfill, 我们就可以使用es6方法来编写了,但是缺点就是会造成全局空间污染 > **babel-runtime**:它不会污染全局对象和内置对象的原型,比如说我们需要Promise,我们只需要import Promise from 'babel-runtime/core-js/promise'即可,这样不仅避免污染全局对象,而且可以减少不必要的代码。虽然 babel-runtime 可以解决 babel-polyfill中的避免污染全局对象,但是它自己也有缺点的,比如上,如果我现在有100个文件甚至更多的话,难道我们需要一个个文件加import Promise from 'babel-runtime/core-js/promise' 吗?那这样肯定是不行的,见下文: #### 3..babel-plugin-transform-runtime > 因此这个时候出来一个 叫 babel-plugin-transform-runtime,它就可以帮助我们去避免手动引入 import的痛苦,并且它还做了公用方法的抽离。比如说我们有100个模块都使用promise,但是promise的polyfill仅仅存在1份。这就是 babel-plugin-transform-runtime 插件的作用。 #### 4. babel-preset-env > babel-preset-env 与 babel-preset-latest的行为相同, ​ 注:`babel-preset-es2015: 可以将es6的代码编译成es5,babel-preset-es2016: 可以将es7的代码编译为es6.babel-preset-es2017: 可以将es8的代码编译为es7.babel-preset-latest: 支持现有所有ECMAScript版本的新特性,但是我们随着时间的推移,将来可能会有跟多的版本插件,比如 bebel-preset-es2018,.... 等等。因此 babel-preset-env 出现了,它的功能类似于 babel-preset-latest,它会根据目标环境选择不支持的新特性来转译` #### 5.babel-presets-stage-x ​ `官方预设(preset), 有两种,一个是按年份(babel-preset-es2017),一个是按阶段(babel-preset-stage-0)。 这主要是根据TC39 委员会ECMASCRPIT 发布流程来制定的。因此到目前为止 有4个不同的阶段预设,一般我们引用stage2 ` ​ 则只需要配置`babel-preset-env`和 `babel-plugin-transform-runtime` 即可解析ES6,7,8.... ​ ``` //.babelrc文件 { "presets": [["env", { "modules": false }], "stage-2"], "plugins": [ [ "transform-runtime", { "polyfill": false } ], "transform-vue-jsx"], } ``` ### 2.压缩JS ​ `webpack.optimize.UglifyJsPlugin`: 压缩JS文件中的空格 ​ `compression-webpack-plugin`: 开启gzip压缩 ​ ```js const webpack = require('webpack') { plugins; [ new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, }, sourceMap: false, }), new CompressionWebpackPlugin({ asset: "[path].gz[query]", algorithm: "gzip", test: new RegExp("\\.(" + ["js", "css"].join("|") + ")$"), threshold: 100, minRatio: 0.8, }), ] } ``` ​ ## 三 路径处理 ​ [关于路径问题]: https://www.jianshu.com/p/775bc50c55c7 ### 1.utl-loader ​ 处理图片,iconfon文件,打包到指定文件夹. ​ ```js { output: { path: path.resolve(__dirname, '../book-html'), filename: path.posix.join('static', '[name].js'), publicPath: "", }, module: { rules: [ { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { limit: 1000, name: path.posix.join('static', '/img/[name].[ext]'), publicPath: "../../", // 改写css中引入的url } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: "url-loader", options: { limit: 1000, name: path.posix.join("static", "/fonts/[name].[ext]"), }, }, ] }, } ``` ### 2.output ```js { output: { filename: path.posix.join('satic', '[name].js'), path: path.resolve(__dirname, '../book-html'), //所有输出文件的目标路径;打包后文件在硬盘中的存储位置。 publicPath: '/'//并不会对生成文件的路径造成影响,主要是对你的页面里面引入的资源的路径做对应的补全 } } ``` ### 3,extract-text-webpack-plugin 的publicPath > 提取css文件中图片资源路劲补全作用 ## 三: 开启本地开发服务 ### 1.webpack-dev-server [配置详情]: https://www.jianshu.com/p/3a779ba3b7ca 1.配置脚本 `*"dev"*: "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"` 2.配置webpack-dev-server的配置 ``` // webpack.dev.config.js const webpackDevServerConfig = { entry: {}, ... devServer: { hot: true, inline: true, contentBase: false, // since we use CopyWebpackPlugin. compress: true, host: "localhost", port: "1111", open: true, overlay: true ? { warnings: false, errors: true } : false, publicPath: "/", proxy: {}, quiet: true, // necessary for FriendlyErrorsPlugin watchOptions: { poll: false, }, }, plugins: [ new webpack.HotModuleReplacementPlugin(), ] } ``` ## 四: 多文件多入口打包 ### 1.多入口entry ​ `多少个需要打包的单个html页面,就设置多少个enrty` ```js // config.js const getEntries = (dir) => { let result = fs.readdirSync(path.resolve(__dirname, dir)); let entry = {}; result.forEach((item) => { let stats = fs.statSync(path.join(__dirname, dir, item)); // 读取文件 let isDir = stats.isDirectory(); // 判断文件还是文件夹 if (isDir) { entry[item] = path.resolve(__dirname, dir, item, `${item}.js`); } }); return entry; } module.exports = { entry: getEntries('../src') } ``` 2. ### 处理多文件html模板 > 相应的入口文件对应相应的html模板 ```js const getHtmlWebpackConfig = (dir) => { let result = fs.readdirSync(path.resolve(__dirname, dir)); let htmlWebpackArr = []; result.forEach((item) => { let selfTemplatePath = path.join(__dirname, dir, item, `${item}.html`); try { let stats = fs.statSync(path.join(__dirname, dir, item)); if (stats.isDirectory() && item !== "assets") { // 判断是文件夹 let res = fs.accessSync(selfTemplatePath); htmlWebpackArr.push( new HtmlWebpackPlugin({ template: selfTemplatePath, // 模板所在的位置 filename: `${item}.html`, // 打包之后模板名称 chunks: ["manifest", "vendor", item], }) ); } } catch (err) { console.log(chalk.red(`${item}文件夹下未发现${item}.html文件!`)); } }); return htmlWebpackArr; }; module.exports = { plugins: [ ...getHtmlWebpackConfig() ] } ``` ### 3.css,js,png,iconfont解析和压缩和单文件入口打包一样 webpack热跟新原理 大概流程是我们用webpack-dev-server启动一个服务之后,浏览器和服务端是通过websocket进行长连接,webpack内部实现的watch就会监听文件修改,只要有修改就webpack会重新打包编译到内存中,然后webpack-dev-server依赖中间件webpack-dev-middleware和webpack之间进行交互,每次热更新都会请求一个携带hash值的json文件和一个js,websocker传递的也是hash值,内部机制通过hash值检查进行热更新, 至于内部原理,因为水平限制,目前还看不懂 webpack工作原理 [https://segmentfault.com/a/1190000012840742]: