从零学习webpack4.0模块打包工具

739 阅读10分钟

首先webpack是一个基于nodejs的打包工具,使用webpack,可以使我们的代码耦合度降低。拆分成模块化开发。

1.webpack究竟是什么

以前我们操作dom,需要把js代码全部写在一起,但是这样很不容易管理和维护,所以出现了webpack我们可以将文件按需导入和导出,用webpack会帮我们根据他的语法生成对应的代码。

相关语法可查看webpack官方文档:中文文档

2.webpack正确安装方式

在需要使用webpack打包的项目目录执行npm安装

局部安装 npm i webpack webpack-cli -S
全局安装 npm i webpack webpack-cli -D
安装指定版本 npm i webpack@4.3.5 webpack-cli -S
删除 npm  uninstall  webpack  -g
查看当前webpack版本 npx webpack -v
使用webpack打包文件 npx webpack index.js

npx执行的当前项目目录下node_moudels中的webpack。

注意:webpack安装最好不要全局安装,以防版本混乱导致报错。

3.如何使用webpack

1.首先我们需要使用npm命令初始化一个项目

按需生成   npm init
默认初始化 npm init -y

此时项目文件夹下会出现一个package.json文件,里面包含了一些项目信息

{
    "name": "dome01",------------------------项目名称
    "version": "1.0.0",----------------------版本号
    "description": "", 
    "main": "a.js",--------------------------项目入口文件,可删除
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {},---------------------上线环境依赖包
    "devDependencies": {--------------------开发环境依赖包
        "webpack": "^4.43.0",
        "webpack-cli": "^3.3.11"
    }
}

2.局部安装webpack和webpack-cli

npm i webpack webpack-cli -S

此时文件夹下会出现node_moudles文件夹,里面包含了一些webpack的依赖包。

3.接下来我们就可以在项目中按照webpack的api来书写项目代码啦。

写完后通过

npm webpack 项目路径 

来打包项目。

4.webpack打包原理

到目前为止,我们知道webpack打包直接执行npx webpack 项目路径 就可以生成dist目录,完成打包工作,但是这是为什么呢?这是因为webpack本身就有一套默认的打包文件,他会默认按照他的意思去打包。

但是通常开发环境下,我们需要自己配置打包需求。 当我们执行 npx webpack 如果不指定打包文件,控制台就会报错,其实执行命令的时候webpack会自动去项目路径下面寻找打包的配置文件,webpack.config.js文件,找到并去执行他它。

1.首先,我们需要在项目路径下面创建一个webpack.config.js文件

const path = require('path')---------------------------导入node读文件api
module.exports = {
    entry: './abc.js',---------------------------------入口:需要打包的文件路径
    output: {------------------------------------------出口:打包完成的文件配置
        filename: 'aaa.js',----------------------------打包完成后生成的js文件
        path: path.resolve(__dirname,'aaa')-----------打包完成后aaa.js放置的位置,
        __dirname,表示当前项目目录下,aaa表示生成的文件夹名字,不设置的话,默认是dist文件夹。
    }
}

执行npx webpack 后可发现文件目录多出了aaa文件夹。

5.npm工具为我们提供了方便偷懒的script模块

在package.json文件目录中有一个script对象,在这里面我们可以使用定义我们自己的命令,通过 npm run 来快速运行它

{
    "name": "dome01",
    "version": "1.0.0",
    "description": "",
    "main": "a.js",
    "scripts": {
      build : webpack 或 npx webpack ,-------因为script默认寻找webpack会去node_modlues中去找依赖,所以不加npx也不用担心会使用到全局的webpack。
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {},
    "devDependencies": {
        "webpack": "^4.43.0",
        "webpack-cli": "^3.3.11"
    }
}

6.我们可以自己配置想要的webpack打包方式

1.一般情况下,我们会把需要打包的项目文件放到src目录下

2.配置我们自己的webpack.config.js文件

const path = require('path')
module.exports = {
    entry: './src/index.js',--------我们也可以直接写 './src',默认回去找src下的index.js文件
    output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, 'aaa')
    }
}

3.执行npm run build 可以看到打包成功

7.使用Loader打包静态资源文件 (图片篇)

因为webpack默认只能打包.js文件,其他像.css、.vue、.jpg|.png这样的文件无法打包,此时我们需要引入他们对应的loader来完成打包工作。

1.首先我们需要在webpack.config.js文件中配置module模块

const path = require('path')
module.exports = {
    entry: './src',
    output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {--------------------------------------------此处配置loader
        rules: [{----------------------------------------loader规则,数组包含多个loader
            test: /\.(jpg|png)$/,--------------------正侧匹配以.jpg .png结尾的文件进行打包
            use: {---------------------------------------打包的配置
                loader: 'file-loader',-------------------使用的打包loader
                options: {-------------------------------打包输出时的配置
                    name: '[name].[ext]',----------------打包文件输出名字,[name]表示原始名字,[]表示用原始文件后缀               
                    outputPath: './img/',----------------打包后的文件放在dist目录下的img文件夹下
                }
            }
        }]
    }
}

2.使用前我们需要安装对应的loader

npm i file-loader -D

不懂查看官方文档的filer-loader部分

3.执行npm run build完成打包,生成目录结构如下

8.file-loader和url-loader的区别

在使用file-loader打包文件时,生成的文件总是会存在于dist目录下,但是如果使用了url-loader来实现文件的打包,我们可以通过在options中配置limit属性来限制文件输出的地方。

1.首先webpak.config.js代码配置如下

const path = require('path')
module.exports = {
    mode: 'development',------------为了出去浏览器警告,写上mode,可以控制打包生成的文件时development环境(未压缩),还是production环境(会压缩)
    entry: './src',
    output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',--------------引入url-loader
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb-------限制图片大小为300kb,若图片小于300kb则,将图图片打包进js代码中(可减少发送http请求次数),若图片大于300kb,则按照file-loader方式打包如dist文件目录下
                }
            }
        }]
    }
}

url-loader可以智能的根据图片的大小来决定图片打包的方式,若图片小,可以写入js代码中,从而来减少http求情次数。若图片大,则写入文件目录,防止写入js中,因为js过大而导致页面白屏时间过长。

9.使用Loader打包静态资源文件 (样式-上篇)

如果想要实现对css样式进行打包,则需要使用style-loader和css-loader

1.使用style-loader和css-loader解析样式

1.首先同样在webpack.config.js文件下配置rules

const path = require('path')
module.exports = {
    mode: 'development',
    entry: './src',
    output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.css$/,---------------------识别以.css为结尾的文件
            use: [{
                    loader: 'style-loader'------后执行style-loader将编译的css样式插入页面head表签中的style中
                },
                {
                    loader: 'css-loader'------先执行css-loader解析webpack方式引入的css中的代码
                }
            ]
        }]
    }
}

2.安装安装style-loader和css-loader

2.使用sass预编译器配置sass-loader

1.只需在package.json文件中加入sass-loader即可,注意顺序,webpack解析自下而上

const path = require('path')
module.exports = {
    mode: 'development',
    entry: './src',
    output: {
        filename: 'aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader'
                },
                {
                    loader: 'sass-loader'
                }
            ]
        }]
    }
}

即可使用sass语法书写css样式

2.安装 sass-loader和node-sass

npm install sass-loader node-sass webpack --save-dev

安装 node-sass可能会报错,是由于GitHub资源太烂,此时使用淘宝镜像地址安装node-sass

npm i node-sass -D  --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/

3.css文件,使用.scss后缀,不要使用.sass后缀,会报错。

打包后文件目录:

3.使用postcss-loader给css样式增加浏览器前缀

1.首先,我们需要在项目目录下创建一个postcss.config.js文件

里面写入postcss-loader的依赖配置,当打包文件执行到postcss-loader的时候将会执行postcss.config.js文件。

2.我们需要先安装autoprefixer插件。

npm i autoprefixer -D

3.在postcss.config.js中使用它。

module.exports = {
    plugins: [
        require('autoprefixer')------------------------------引入autoprefixer插件
    ]
}

4.局部安装postcss-loader并且引用

npm i postcss-loader -D

webpack.config.js文件中加postcss-loader。

const path = require('path')
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader'
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'--------------------------末尾加postcss-loader
                }
            ]
        }]
    }
}

5.即可发现打包的css代码中加入了浏览器前缀

10.使用Loader打包静态资源文件 (样式-下篇)

1.打包.scss文件可能会遇到的坑

有些时候,我们会在.scss文件中引入其他的scss文件,如果此时我们去执行npm run build打包可能会报错,这是因为,打包时碰到improt '...scss' 时,webpack会依次从下到上去执行post-loader、 sass-loader、 css-loader、 style-loader ,当它执行到sacc-loader后,准备去执行css-loader时,此时在文件中又出现了import导入的.scss结尾的文件时,他就不知道怎么去处理它了。 此时我们需要配置css-loader,给它增加improtLoaders属性,告诉webpcak,你应该返回前n层,重新过一遍loader。

webpack.config.js文件配置如下

const path = require('path')
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2------------------------------从前两个loader开始执行
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    }
}

2.css-loader 实现css模块化引用,类似与vue的scoped属性

令css-loader的modules属性值为true,即可开启css模块化

{
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        modules: true----------------------开启css模块化
                    }
                },

3.使用file-loader打包font字体图标

1.首先我们去iconfont官网下载所需的字体图标文件

~我们需要保留iconfont.eot iconfont.svg iconfont.ttf iconfont.woff 这四个文件到src/font目录下。

~将iconfont.css改为iconfont.scss。

~更改iconfont.scss中的文件路径

2.webpack.config.js文件中加入rules配置file-loader

const path = require('path')
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,------------------打包iconfont字体图标
            use: {
                loader: 'file-loader',
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true-------------------css模块化不用先暂且关掉,以防影响打包。
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    }
}

3.html页面中使用font图标

添加类名使用 :<div class="iconfont icon-nan"></div>
添加伪类使用 :需要使用的元素类中加入iconfont同时添加 ::before {content: '\e8b4'; }

11.webpack中plugin(插件)的使用

webpack中plugin就像我们vue中生命周期钩子函数的存在,这些插件会在webpack执行的打包过程中执行某些操作

1.html-webpack-plugin(webpack打包结束后执行)

因为在webpack打包时,html页面并没有一起进入到打包好的dist目录下,此时需要我们添加html-webpack-plugin插件来完成打包完成后自动添加html页面的操作。

1.首先我们需要安装html-webpack-plugin

npm i html-webpack-plugin -D

2.我们需要在webpack.config.js文件的plugin中去配置它,要想使用插件,我们先需要使用commonjs语法引入它先。然后去初始化它。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')-------引入html-webpack-plugin插件
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin()]---------------------------使用插件
}

2.执行npm run build 后我们发现页面下多了index.html文件,且帮我们引入了打包的js文件。

index.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <script src="js/aaa.js"></script>-----------------自动引入打包好的js
</body>

</html>


可惜的是,这只是模板,它并没有帮我挂在body内的所写的dom元素

3.针对第二部的问题,我们需要对html-webpack-pulgin进行配置

1.首先我们需要在src目录下创建一个html模板,里面写入我们所需要的dom
2.其次,在html-webpack-pulgin中引入

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
                options: {
                    outputPath: './font/'
                }
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin({
        template: './index.html'-----------------------------------引入想使用的html模板
    })]
}

2.clean-webpack-plugin(打包开始前执行)

以前打包我们会发现每一次打包只会跟新文件夹,不同名的文件不会覆盖,有了clean-webpack-plugin插件,可以发现每次打包前,该插件会帮助我们去删除之前的dist目录。

1.安装CleanWebpackPlugin

npm i clean-webpack-plugin -D

2.引入并且使用它,引入方式需要使用es6解构语法

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require("clean-webpack-plugin")--------es6解构引入clean-webpack-plugin
module.exports = {
    mode: 'development',
    entry: './src/index.js',
    output: {
        filename: 'js/aaa.js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
                options: {
                    outputPath: './font/'
                }
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin({
        template: './index.html'
    }), new CleanWebpackPlugin()]------------------使用该插件
}

12.webpack可以同时打包多个js文件

1.修改入口entry和出口output

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
module.exports = {
    mode: 'development',
    entry: {----------------------------------如果不配置output的filename时,entry也不配置入口文件名时,默认打包出的js文件名为main.js
        index: './src/index.js',
        a: './src/a.js'
    },
    output: {
        filename: '[name].js',----------------[name],表示使用entry中定义的属性名
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
                options: {
                    outputPath: './font/'
                }
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin({
        template: './index.html'
    }), new CleanWebpackPlugin()]
}

2.打包后输出结果

13.devtool快速定位错误

使用source-map,运行打包后代码,可以定位错误到开发目录src下

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const { SourceMapDevToolPlugin } = require('webpack')
module.exports = {
    mode: 'development',
    devtool:'cheap-module-eval-source-map',---------------------------------------配置devtool为source-map
    entry: {
        index: './src/index.js',
        a: './src/a.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'aaa')
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
                options: {
                    outputPath: './font/'
                }
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin({
        template: './index.html'
    }), new CleanWebpackPlugin()]
}

注意:devtool错误映射的配置不同的有许多不一样的地方具体查看,官方文档devtool配置参数

>>> 一般情况下如果我们是开发环境(development)一般我们配置为:

devtool:'cheap-module-eval-source-map'

>>> 如果我们是上线环境(production)一般我们调试时配置为:

devtool:'cheap-module-source-map'

14.webpack中的devServer

相信大家都知道,在书写vue的代码时,每次保存项目都会重新启动项目,这就是webpack中的devserver帮我们完成的。

平时我们书写代码,会肯苦逼,每次修改代码,想看效果,都需要重新npm run build 和刷新页面,这样会大大降低我们的开发效率,那么有什么方法可以使我们提高开发效率呢?在这里我介绍三种方式。

第一种: 在package.json文件中script标签下重新配置一下偷懒代码。

"scripts": {
        "build": "webpack --watch"--------------------------加上--watch即可
    },

缺点:每次保存需要自己刷新页面

第二种:(推荐使用)devServer

1.首先我们需要安装webpack-dev-server

npm i webpack-dev-server -D

2.然后我们需要在webpack.config.js中配置devServer

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const { SourceMapDevToolPlugin } = require('webpack')
module.exports = {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    entry: {
        index: './src/index.js',
        a: './src/a.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    devServer: {-----------------------------------------------server服务
        contentBase: "./dist",--------------------------------设置服务器启动作用与的目录
        open: true--------------------------------------------执行启动服务后直接打开浏览器
    },
    module: {
        rules: [{
            test: /\.(eot|ttf|woff|svg)$/,
            use: {
                loader: 'file-loader',
                options: {
                    outputPath: './font/'
                }
            }
        }, {
            test: /\.(jpg|png)$/,
            use: {
                loader: 'url-loader',
                options: {
                    name: '[name].[ext]',
                    outputPath: './img/',
                    limit: 300000 //30万字节=300kb
                }
            }
        }, {
            test: /\.scss$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        importLoaders: 2,
                        // modules: true
                    }
                },
                {
                    loader: 'sass-loader'
                },
                {
                    loader: 'postcss-loader'
                }
            ]
        }]
    },
    plugins: [new HtmlWebpackPlugin({
        template: './index.html'
    }), new CleanWebpackPlugin()]
}

3.在package.json文件中配置srript指令

 "scripts": {
        "build": "webpack",
        "dev": "webpack-dev-server"--------------------npm run dev 启动服务
    },

优点:使用devserver可以使我们高效开发,同时他还能帮我们实现ajax请求。

其他地方可以查阅文档devserver文档

15.如何在devServer中完美接解决开发时的跨域问题

由于浏览器的同源策略,导致端口或者域名不同的两个服务器不能相互访问,这就导致了在前后端分离的项目中,开发时前端不能顺利拿到后端返回的接口数据。

所以我们可以通过给webpack中的devServer配置代理属性proxy来实现,接口的代理映射。经过这层配置后,我们就可以完美的拿到后台的接口数据啦。

可结合官方文档proxy部分:官方文档-proyx

1.首先我们在webpack.config.js中添加代理配置

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin') //给dist目录下加入src页面下的html文件
const { CleanWebpackPlugin } = require("clean-webpack-plugin") //每次打包前删除dist目录

module.exports = {
    mode: 'development',
    devtool: 'cheap-module-eval-source-map',
    entry: {
        index: './src/index.js',
        a: './src/a.js'
    },
    output: {
        filename: '[name].js',
        path: path.resolve(__dirname, 'dist')
    },
    devServer: {
        contentBase: path.join(__dirname, "dist"),
        open: true,
        host: "127.0.0.1",
        port: 9000,
        proxy: {
            '/api': {-------------------------我们通过/api来代表地址中的target,所以在axios访问接口的url地址中,用/api来替换http://localhost:3000/api
                target: 'http://localhost:3000/api',
                changeOrigin: true, // -----target是域名的话,需要这个参数。开启代理
                secure: false, // 设置支持https协议的代理
                pathRewrite: {
                    '^/api': '/' //这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
                }
            },

        }
    },
  

2.写好代理之后,我们重启项目即可访问接口

测试接口:

准备一个可以返回数据的接口:localhost:3000/api/blog/list------------------获取博客列表

通过axios来访问

 import A from './a.js'
 import B from './b.js'
 import C from './c.js'
 import timg from './timg.jpg'
 import "./css/index.scss"
 new A()
 new B()
 new C()
 const root = document.querySelector('.root')
 let img = document.createElement('img')
 console.log(timg)
 img.src = timg
 root.appendChild(img)
 console.log(1122234123123222223344)
 const axios = require('axios')----------------------------引入axios,使用时记得npm安装
 axios({
     method: 'get',
     url: '/api/blog/list'-----------------------------访问代理地址
 }).then((backdata) => {
     console.log(backdata)----------------------------接口返回数据打印到控制台
 })

3.npm run dev 运行项目后控制台可见。

终于没有跨域错误啦!!!

注意:proxy的代理服务,只适用于开发环境下,因为webpack不可能上线部署,所以,在上线的环境下,还是需要解决跨域问题的,具体怎么解决,一般都是后台来完成。

16.使用<script>标签的src属性解决跨域问题

此方法需要后台协助可以看这篇文章,我觉得写的很详细,我就偷一波懒

点击查看

17.webpack,devSever之热加载

有的时候我们在修改样式或者修改js代码时,不想每次改变页面都要重新刷新,而是只去局部改变。有一点特别明显的大概就是当我绑定了事件,删除修改某个节点,但是修改样式,页面一刷新,所有的节点都不见了,又要重新来,这很烦。

所以,我们使用了热加载来实现这一功能

1.首先配置webpack.config.js中的devServer

 devServer: {
        contentBase: path.join(__dirname, "dist"),
        open: true,
        host: "127.0.0.1",
        port: 9000,
        hot: true,---------------------------开启热加载
        hotOnly: true,----------------------即使修改错误,页面也不要刷新
        proxy: {
            '/api': {
                target: 'http://localhost:3000/api',
                changeOrigin: true, // target是域名的话,需要这个参数,
                secure: false, // 设置支持https协议的代理
                pathRewrite: {
                    '^/api': '/' //这里理解成用‘/api’代替target里面的地址,后面组件中我们掉接口时直接用api代替 比如我要调用'http://40.00.100.100:3002/user/add',直接写‘/api/user/add’即可
                }
            },

        }
    },

2.其次我们还要引入HotModuleReplacementPlugin插件,这个插件时webpack内置的,所以不需要安装

plugins: [new HtmlWebpackPlugin({
            template: './index.html'
        }),
        new CleanWebpackPlugin(),
        new webpack.HotModuleReplacementPlugin()--------------------引入插件
    ],

3.重启npm run dev

你就可以感受了

18.babel的使用

由于我们编写代码时,大部分还是es6的语法,我们需要使用babel来将他翻译为es5语法

1.安装

npm install --save-dev babel-loader @babel/core

2.webpack配置文件webpack.config.js文件修改

    module: {
        rules: [{
                test: /\.(eot|ttf|woff|svg)$/,
                use: {
                    loader: 'file-loader',
                    options: {
                        outputPath: './font/'
                    }
                }
            }, {
                test: /\.(jpg|png)$/,
                use: {
                    loader: 'url-loader',
                    options: {
                        name: '[name].[ext]',
                        outputPath: './img/',
                        limit: 300000 //30万字节=300kb
                    }
                }
            }, {
                test: /\.scss$/,
                use: [{
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            importLoaders: 2,
                            // modules: true
                        }
                    },
                    {
                        loader: 'sass-loader'
                    },
                    {
                        loader: 'postcss-loader'
                    }
                ]
            },
            {-----------------------------------------------加入babel-loader
                test: /\.js$/,
                exclude: /node_modules/,------------------跳过node_modules
                loader: "babel-loader"
            }
        ]