# fed-e-task-02-02 **Repository Path**: sfljskeprim_admin/fed-e-task-02-02 ## Basic Information - **Project Name**: fed-e-task-02-02 - **Description**: No description available - **Primary Language**: JavaScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-08-31 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # fed-e-task-02-02 ## 1、Webpack 的构建流程主要有哪些环节?如果可以尽可能的描述Webpack打包的整个过程 webpack以JavaScript驱动整个前端业务,解析每个依赖模块的资源,加载结果到统一的输出文件bundle.js,例如入口文件是main.js,代码如下: ```javascript import createHeading from './heading.js'//导入js文件 import './main.css'//导入css文件 import icon from './1.jpg';//导入文件资源 import footerHtml from './footer.html';//导入HTML文件 html字符串 需要使用html-loader ``` webpack构建过程: - 根据配置文件,识别入口文件 - 逐层识别模块依赖(ES Module 标准的import、遵循CommonJS 标准的require函数、遵循AMD标准的define函数和require函数、*样式代码中的@import指令和url函数、*HTML代码中图片标签的src属性) - 通过Loader加载器处理文件,转换编译代码 - 通过Plugin 解决其他自动化工作 ;eg:清除dist目录;拷贝静态文件值输出目录;压缩输出代码 详细的构建流程如下: 1. 配置文件:配置入口文件和输出文件的路径 ```javascript mode:'none', //指定打包入口文件路径 entry: './src/main.js', //指定输出文件的路径-就是编译后的js output: { filename:'bundle.js', path:path.join(__dirname,'dist'), publicPath:'dist/'//网站的根目录 用于资源目录 否则无法找到资源文件 } ``` 2. 配置Loader处理文件 - webpack默认会自动处理js文件的ESM模块,其他的文件需要使用Loader进行加载。 - 加载CSS文件需要使用css-loader style-loader ```javascript { test:/.css$/,//匹配文件 use:[//配置多个loader是从后往前执行 一定要先执行css-loader 'style-loader', // 把css-loader编译后的结果 通过style标签的形式追加到界面上 'css-loader' // ],//该文件使用的加载器 yarn add style-loader --dev } ``` - 加载html文件需要使用html-loader ```javascript { test:/\.html$/, use:{ loader:'html-loader', options:{ // attrs: ['img:src','a:href']//对HTML的属性处理 此处是老版本的写法 由于新版本升级不再是这个写法了 //1.2.1 版本 //如果传递boolean True 值允许处理所有默认元素和属性,false 禁用处理所有属性。 //如果传递object则进行处理 attributes:{ list:[ { tag:'img', attribute:'src', type:'src' }, { tag:'a',//对应的标签名 attribute:'href',//对应的属性名 type:'src'//对应的属性类型 } ] } } } } ``` - 加载一些文件资源需要使用file-loader ```javascript { //Data url 的方式表示文件 test:/.jpg$/, use:{ loader:'url-loader', options:{ limit:10 * 1024 //限制10KB一下的文件交给url-loader 大于10KB的文件使用file-loader 一定要安装file-loader模块 } } } ``` - webpack不能处理ES2015,因为模块打包需要webpack默认处理了import和export,但是不能转换代码中的ES6特性,需要使用babel-loader进行加载处理,由此webpack的构建核心需要依赖于Loader ```javascript { test:/.js$/, use:{ loader:'babel-loader', options:{ presets:['@babel/preset-env'] } } } ``` 注意: Webpack 模块加载方式 - ES Module 标准的import - 遵循CommonJS 标准的require函数 - 遵循AMD标准的define函数和require函数 - *样式代码中的@import指令和url函数 - *HTML代码中图片标签的src属性 3. 配置plugin解决一些自动化的工作,如下配置:自动清除输出目录,拷贝资源文件到输出目录,配置HTML模板等 ```javascript plugins: [ new CleanWebpackPlugin(), // 新版本API 发生变化 new CopyWebpackPlugin({ patterns:[ {from:'public',to:'public'} ] }), // 如果存在html-loader 配置会发生错误?? why为什么呢? new HtmlWebpackPlugin({ title:'Webpack plugins sample', meta:{ viewport: 'width=device-width' }, //设置一个模板去加载 template:'./src/template.html' }), //输出多个页面文件 about new HtmlWebpackPlugin({ filename:"about.html",//默认是index.html title:'Webpack plugins sample', meta:{ viewport: 'width=device-width' }, //设置一个模板去加载 template:'./src/template.html' }), new MyPlugin() ] ``` 通过上述的处理,最后webpack会打包输出bundle.js这个文件是核心文件,包括了核心代码比如模块导入、css、资源文件等等,如果配置了html-webpack-plugin会根据设置或者设置的模板自动生成一个html文件 配置文件 -> loader -> plugin -> 打包输出 ## 2、Loader和Plugin有哪些不同?请描述一下开发Loader和Plugin的思路 Loader 专注实现资源模块的加载 Plugin 专注解决其他自动化工作 ;eg:清除dist目录;拷贝静态文件值输出目录;压缩输出代码 - 开发Loader思路 首先开发Loader通过module.exports返回一个函数,而这个函数中有一个source的参数,source是webpack传递过来匹配到文件的文件内容,我们知道一个Loader一定要设置匹配文件的正则表达式,当拿到source就可以对文件内容进行处理,注意当我们对这个文件内容处理后这个函数最终返回的是一个JavaScript代码块或者交给下一个loader处理 比如这样: ```javascript { test:/.md$/, use: [ 'html-loader', './markdown-loader'//先执行的loader放在最后 ] } ``` ```javascript const marked = require('marked'); module.exports = source => { console.log('??',source); //只能返回一个 javascript代码 / 下一个loader处理 other-loader // return 'console.log("hello ~")' const html = marked(source); // return `module.exports=${JSON.stringify(html)}` // ES Module导出 // return `export default ${JSON.stringify(html)}` //返回HTML字符串 交给下一个html-loader处理 return html } ``` - plugin的开发思路 插件是webpack的支柱功能,插件的目的在于解决loader无法实现的其他事 插件必须是一个函数或者是一个包含apply方法的对象,apply方法会被webpack compiler调用,并且在整个编译生命周期都可以访问compiler,compiler hook的tap方法是实现插件功能的核心方法,第一个参数是驼峰式命名的插件名称,第二个参数是插件功能的实现 - 通过compilation的assets获取打包的所有文件信息 - 文件的内容通过compilation.assets[key].source()获取 - 修改文件内容后,设置compilation.assets[key]对象的值必须要设置:source方法,size方法 ```javascript class MyPlugin{ apply(compiler){ console.log('MyPlugin 启动'); compiler.hooks.emit.tap('MyPlugin',compilation=>{ //此次打包过程的上下文 compilation //assets 获取打包的文件信息 for (const key in compilation.assets) { console.log(key);//key资源文件的名称 //拦截.js文件 if(key.endsWith('.js')){ const contents = compilation.assets[key].source();//获取文件内容 const withoutComments = contents.replace(/\/\*\*+\*\//g,''); compilation.assets[key] = { source: ()=>withoutComments, size:()=>withoutComments.length } } } }) } } ```