关于webpack-dev-server:vue批量导入文件篇一

序言在咱们创立路由的时候,会发现如果所有的路由都在一个文件内,那么当我的项目路由多的时候,就会呈现路由难找,路由跟路由不在一块等状况呈现(没保护好)。所以,为了防止这种状况,咱们能够应用模块化这种思维来解决问题。那么,问题就来了,当模块多的时候,一个个的导入就很浪费时间,须要反复 引入 - 赋值 这一过程,所以,咱们是不是能让程序来帮咱们做这一步骤呢,那么咱们岂不是能够欢快游玩了。 一、webpackrequire.context依照官网解释,该办法能够在构建时在代码中解析要搜寻的目录。艰深的来说,就依据你给出的规定,而后找到符合条件的文件,而后在构建的时候主动生成咱们之前须要手动导入的那些代码。 /** * 能够看出该办法承受4个参数 * @param {string} directory 须要搜寻的目录 * @param {boolean} useSubdirectories 是否搜寻子目录,默认true * @param {regExp} regExp 文件匹配规定 默认/^\.\/.*$/ * @param {string} mode 模式,默认sync * @return {function} function(resolve, keys, id) */require.context( directory, (useSubdirectories = true), (regExp = /^\.\/.*$/), (mode = 'sync'))/** * 该办法返回一个函数,具备 3 个属性:resolve、keys、id * resolve{function},返回解析申请的模块 ID * keys{function},返回正则匹配的文件名称数组 * id{string},上下文模块的模块 ID */// 例子,搜寻当前目录下的modules,不须要搜寻modules子目录,匹配规定是所有的js文件require.context('./modules', false, /\.js$/);/** * 残缺例子,主动导入路由模块 * 目录 * --> modules * ---- home.js * ---- system.js */(r => r.keys().map(key => r(key).default))(require.context('./modules', false, /\.js$/))// console[{ path: '/home' name: 'home', component: () => import('@/views/home'),}, { path: '/system' name: 'system', component: () => import('@/views/system'),}]二、viteimport.meta.glob依照官网解释,该办法是一个懒加载办法,通过动静导入实现,与 import.meta.globEager 的区别只是一个同步,一个异步,视状况应用。 ...

March 29, 2022 · 1 min · jiezi

使用webpackdevserver创建mock-server

项目地址:https://github.com/yuanyuansh... 在开发基于 api 交互、前后端分离的网页应用时,经常会遇到几个问题: 前端页面已经编排好了,但是后台接口还没准备好我们希望服务器返回特定类型的数据,以测试某页面在特定条件下是否存在问题,但作为前端我们一般不会接触到后端代码和数据库,每次都找后端添加模拟数据又很麻烦。为解决这两个问题,最简单的解决办法就是搭建一个 mock server,专门返回需要的模拟数据。 webpack-dev-server 是我们开发 vue、react 时必备的工具,既然是一个服务器,那么我们是不是可以让他实现一个 mock server 的功能。 原理:通过 webpack-dev-server 的 before 钩子,可以在 webpack-dev-server 上添加我们需要的 mock server 功能,而不需要另行搭建服务器。 只需要少许修改就能 webpack-dev-server 当做 mock server 来用,并且对同一 URL 下的 GET、POST、PATCH 等不同的 HTTP METHOD 做分别处理,支持热切换。 使用方法很简单,在 webpack.dev.conf.js 的 devServer 中添加新钩子 before,将所有请求交由 apiMocker 处理,然后当需要使用模拟数据时,只需要将请求的 URL 改为 webpack 服务器上既可。项目地址webpack_api_mocker 安装npm install mocker-api --save-dev使用package.json中配置 "dev-mock": "cross-env MOCK=true webpack-dev-server --inline --progress --config build/webpack.dev.conf.js"webpack.dev.conf.js中配置 devServer: { before (app) { if (process.env.MOCK) { apiMocker(app, path.resolve('mock/mocker'), { proxy: apiDomainMap, changeHost: true }) } } }apiDomainMap.js配置 ...

August 21, 2019 · 1 min · jiezi

Webpack重要知识点

最近在系统整理知识点,现将Webpack的一些重要知识点罗列出来,方便快速查阅。Tree Shaking为了使用tree shaking,需要满足以下条件: 使用ES2015语法(即import和export)在项目package.json文件中,添加sideEffects入口引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如:UglifyJSPlugin)将文件标记为无副作用(side-effect-free)这种方式是通过package.json的sideEffects属性来实现的。 { "sodeEffects": false}「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个export或多个export。举例说明,例如polyfill,它影响全局作用域,并且通常不提供export。注意,任何导入的文件都会受到tree shaking的影响。这意味着,如果在项目中使用类似css-loader并导入CSS文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除: { "sideEffects": ['*.css']}压缩输出从 webpack 4 开始,也可以通过 "mode" 配置选项轻松切换到压缩输出,只需设置为 "production"。也可以在命令行接口中使用--optimize-minimize标记,来使用UglifyJSPlugin。 Code Splittingcode splitting的必要性 不进行code splitting,打包后单文件提交较大,加载时长较长,影响用户体验不进行code splitting,经常修改业务代码,重新打包后,浏览器不能进行缓存,导致性能较差,影响用户体验code splitting的配置同步代码方式import _ from 'lodash';webpack.common.js配置如下: ....optimization: { splitChunks: { chunks: 'all' }}....配置后,会将公用类库进行打包,生成一个vendors~main.js文件。 异步代码方式function getComponent() { return import('lodash').then(({ default: _ }) => { var element = document.createElement('div'); element.innerHTML = _.join(['Clear', 'love'], ''); return element; })}getComponent().then(element => { document.body.appendChild(element);})SplitChunksPlugin 配置参数详解魔法注释(magic comment)修改打包动态组件名称1. 使用@babel/plugin-syntax-dynamic-import支持动态引入插件在.babelrc中引用该插件 ...

July 5, 2019 · 2 min · jiezi

vuewebpack40-生产环境手动一步一步配置-持续更新中

vue-webpack介绍 vue+webpack 手动搭建过程,熟悉 webpack 的配置,loader&插件的使用 介绍目标:熟悉 webpack 的配置,loader&插件的使用 通常新建 vue 项目都使用 vue-cli 脚手架,其实对于 webpack 的配置是一知半解,当需要升级 webpack 或者优化项目配置时,就显得很无力。通过手动搭建 webpack 可以对 webpack 有更深入的了解,当我们使用其他模块管理器时(eg:rollup,gulp),也不会那么生疏。 关于 dependencies 和 devDependencies通过 NODE_ENV=developement 或 NODE_ENV=production 指定开发还是生产环境 devDependencies 是只会在开发环境下依赖的模块,生产环境不会被打入包内。 而 dependencies 依赖的包不仅开发环境能使用,生产环境也能使用。其实这句话是重点,按照这个观念很容易决定安装模块时是使用--save 还是--save-dev。 项目包版本项目地址 "dependencies": { "@xunlei/vue-lazy-component": "^1.1.3", "echarts": "^4.2.1", "element-resize-event": "^3.0.3", "element-ui": "^2.7.2", "file-loader": "^4.0.0", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.2.0", "intersection-observer": "^0.7.0", "lodash": "^4.17.11", "url-loader": "^2.0.0", "vue": "^2.6.10", "webpack": "^4.34.0" }遇到的配置错误1.vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.解决办法:Vue-loader 在 15.*之后的版本都是 vue-loader 的使用都是需要伴生 VueLoaderPlugin 的 ...

June 21, 2019 · 5 min · jiezi

Vue@2.6+webpack@4.29.6 打造TODO应用

demo地址:欢迎startdemo截图:简介:此项目首先完成一个前端工程的配置,通过webpack搭建一个完善的vue的workflow,然后基于Vue实现TODOList的简单功能,并涵盖了vue的.vue文件以及jsx的开发模式的了解。使用方法:下载源码git clone https://github.com/1020196987…安装npm依赖npm install进入项目目录&&运行项目npm run start由于安装了webpack-dev-server浏览器会自动打开

March 18, 2019 · 1 min · jiezi

webpack4系列教程(九):开发环境和生产环境

构建开发环境如果你一直跟随我前面的博文,那么你对webpack的基础知识已经有比较深刻的理解了。之前,我们一直执行着:npm run build来打包编译输出我们的代码,本文我们来看看如何构建一个开发环境,来使我们的开发变得方便些。1.1 webpack-dev-serverwebpack-dev-server是一个简单的小型的web服务器,并且能够实时重载,配置也很简单,首先安装:npm install –save-dev webpack-dev-server配置webpack.config.js:devServer: { port: 8080, // 端口号 host: ‘0.0.0.0’, // 主机名,设为该值可通过IP访问 overlay: { errors: true // 错误提示 } }在package.json中添加命令: “dev”: “cross-env NODE_ENV=development webpack-dev-server –config config/webpack.config.js"执行:npm run dev可见我们的服务已经跑起来了:1.2 source-map在webpack打包源码时,我们会很难找到错误的出现位置,比如将源文件 sum.js、minus.js打包到bundle.js中,其中一个源文件出现了错误,仅仅会追踪到bundle.js中,这对我们来说并不理想。因此为了更加便捷的找到错误的原始位置,JavaScript为我们提供了 source-map的功能,将编译后的代码映射回原始源代码。如果一个错误来自于 sum.js,source map 就会明确的告诉你。 我们来测试一下,在sum.js中输出一个错误:// ES Mudule 规范export default function (a, b) { console.error(’this is test’) // 输出错误 return a + b}在没有devtool配置的情况下 npm run dev,会发现错误提示的行数并不准确,原因是我们的代码是被编译过的然后在webpack.config.js中加入配置: devtool: ‘inline-source-map’, // 加入devtool配置当配置文件改动时需要重新执行 npm run dev:错误提示行数以及源码映射都是正确的。devtool的取值有很多,大家可根据需要自行配置1.3 模块热替换模块热替换(Hot Module Replacement)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。使用非常简单,在webpack.config.js中引入webpack: const webpack = require(‘webpack’)在plugins数组中添加: new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin()给devServer中的hot属性设为true:devServer: { port: 8080, // 端口号 host: ‘0.0.0.0’, // 主机名,设为该值可通过IP访问 overlay: { errors: true // 错误提示 }, hot: true }这样我们修改代码的时候就可以局部刷新模块而不是刷新整个页面了。2.构建生产环境开发环境(development)和生产环境(production)的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载(live reloading)或热模块替换(hot module replacement)能力的 source map 和 localhost server。而在生产环境中,我们的目标则转向于关注更小的 bundle,更轻量的 source map,以及更优化的资源,以改善加载时间。由于要遵循逻辑分离,我们通常建议为每个环境编写彼此独立的 webpack 配置。虽然,以上我们将生产环境和开发环境做了略微区分,但是,请注意,我们还是会遵循不重复原则(Don’t repeat yourself - DRY),保留一个“通用”配置。为了将这些配置合并在一起,我们将使用一个名为 webpack-merge 的工具。通过“通用”配置,我们不必在环境特定的配置中重复代码。我们先从安装 webpack-merge 开始,用来合并webpack配置项:npm install –save-dev webpack-merge在config文件夹下创建 webpack.dev.js 和 webpack.build.js 并修改 webpack.config.js,将开发与生产环境的公共配置放在webpack.config.js中:const path = require(‘path’)const HtmlWebpackPlugin = require(‘html-webpack-plugin’)const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)const isDev = process.env.NODE_ENV === ‘development’const config = { entry: { main: path.join(__dirname, ‘../src/main.js’) }, output: { filename: ‘[name].bundle.js’, path: path.join(__dirname, ‘../dist’) }, module: { rules: [ { test: /.(vue|js|jsx)$/, loader: ’eslint-loader’, exclude: /node_modules/, enforce: ‘pre’ }, { test: /.js$/, loader: ‘babel-loader’, exclude: /node_modules/ }, { test: /.vue$/, loader: ‘vue-loader’, options: createVueLoaderOptions(isDev) }, { test: /.ejs$/, use: [’ejs-loader’] }, { test: /.css$/, use: [ isDev ? ‘vue-style-loader’ : MiniCssExtractPlugin.loader, { loader: ‘css-loader’, options: { importLoaders: 1 } }, ‘postcss-loader’ ] }, { test: /.less$/, use: [ isDev ? ‘vue-style-loader’ : MiniCssExtractPlugin.loader, ‘css-loader’, { loader: ‘postcss-loader’, options: { sourceMap: true } }, ’less-loader’ ] }, { test: /.(jpg|jpeg|png|gif|svg)$/, use: [ { loader: ‘url-loader’, options: { name: ‘[path][name]-[hash:5].[ext]’, limit: 1024 } } ] } ] }, plugins: [ new HtmlWebpackPlugin({ template: path.join(__dirname, ‘../index.html’), inject: true, minify: { removeComments: true } }) ]}module.exports = configwebpack.dev.jsconst merge = require(‘webpack-merge’)const common = require(’./webpack.config.js’)module.exports = merge(common, { mode: ‘development’, devtool: ‘inline-source-map’, devServer: { port: 8080, host: ‘0.0.0.0’, overlay: { errors: true }, historyApiFallback: { index: ‘/index.html’ } }})webpack.build.jsconst path = require(‘path’)const CleanWebpackPlugin = require(‘clean-webpack-plugin’)const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)const merge = require(‘webpack-merge’)const common = require(’./webpack.config.js’)module.exports = merge(common, { mode: ‘production’, optimization: { splitChunks: { chunks: ‘initial’, automaticNameDelimiter: ‘.’, cacheGroups: { commons: { name: ‘commons’, chunks: ‘initial’, minChunks: 2, priority: 3 }, vendors: { test: /[\/]node_modules[\/]/, priority: 1 } } }, runtimeChunk: { name: entrypoint => manifest.${entrypoint.name} } }, plugins: [ new MiniCssExtractPlugin({ filename: ‘[name].css’ }), new CleanWebpackPlugin( [‘dist’], { root: path.join(__dirname, ‘../’) } ) ]})修改package.json的命令:“dev”: “cross-env NODE_ENV=development webpack-dev-server –config config/webpack.dev.js”,“build”: “cross-env NODE_ENV=production webpack –config config/webpack.build.js –progress –inline –colors"现在分别执行 npm run dev 和 npm run build 就会得到你想要的了。本人才疏学浅,如有不当之处,欢迎批评指正

January 17, 2019 · 2 min · jiezi

uni-app跨域解决方案

1.官方推荐cors和插件安装解决跨域2.配置uni-app 中 manifest.json->h5->devServermanifest.json “h5”: { “devServer”: { “port”: 8000, “disableHostCheck”: true, “proxy”: { “/dpc”: { “target”: “http://dpc.dapeis.net”, “changeOrigin”: true, “secure”: false } } } }http请求uni.request({ url: ‘/dpc/getUserInfo’, success: (res) => { console.log(res.data); }});这样请求webpack会解析为请求http://dpc.dapeis.net/dpc/参考资料:webpack-dev-serverwebpack跨域API

January 16, 2019 · 1 min · jiezi

[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇

GitHub 完整配置文件地址: https://github.com/yhtx1997/w…由于篇幅过长分三次发布,建议按顺序看[ webpack4 ] 配置属于自己的打包系统教程(一)—— 基础配置篇[ webpack4 ] 配置属于自己的打包系统教程(二)—— 资源配置篇[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇环境配置篇主要内容开发环境生产环境分离实时预览,热更新webpack-dev-server 其他常用代码复用处理开发环境和生产环境到了这一步,该讲讲开发环境模式和生产环境模式了开发环境是自己开发时用的,需要有实时编译功能、模块热替换功能(更新文件不用完全更新页面)、错误提示到具体哪个文件几行生产环境是放到线上给用户使用的,需要代码压缩功能配置代码组件化我们先把之前配置好的 webpack 配置文件改下名,改名 webpack.common.js ,意思是开发环境和生产环境都需要的,将代码压缩之类的挪到生产配置下之后安装 webpack-merge ,官方推荐的是为每个环境写单独的 webpack 文件虽然有简单的方法实现但是依然推荐写单独的配置文件,因为在这样的配置方式你可以更清楚你自己在做什么,还可以让你的配置更加个性(自定义)安装 webpack-mergenpm install webpack-merge -D新建开发环境配置我们新建一个 js 文件,命名为 webpack.dev.js ,添加如下代码const merge = require(‘webpack-merge’);//合并配置const common = require(’./webpack.common.js’);//引入公共配置 module.exports = merge(common, { mode: ‘development’,//声明是开发环境 //关于 dev 的配置 })新建开发环境配置我们新建一个 js 文件,命名为 webpack.prod.js 添加如下代码const merge = require(‘webpack-merge’);//合并配置const UglifyJSPlugin = require(‘uglifyjs-webpack-plugin’);//用来压缩 js 代码const common = require(’./webpack.common.js’);//引入公共配置module.exports = merge(common, { mode: ‘production’,//声明是生产环境 //关于 prod 的配置});开发环境实时预览跟着配置并操作的小伙伴可能发现了,每次修改后都需要手动在命令行输入命令,并且还要刷新浏览器才能看到最新的效果 那么现在来解决这两个问题,方法就是使用 webpack-dev-server安装npm install webpack-dev-server -D配置实时预览模块热更新自定义请求代理自定义 ip 及端口注:使用 webpack-dev-server 并不会编译到本地文件,而是放到内存中const merge = require(‘webpack-merge’);const common = require(’./webpack.common.js’);const path = require(‘path’);const webpack = require(‘webpack’); module.exports = merge(common, { mode: ‘development’, plugins: [ new webpack.NamedModulesPlugin(),//模块热更新 new webpack.HotModuleReplacementPlugin()//模块热更新 ], devServer: { contentBase: path.join(__dirname, ‘dist’),//预览的目录,写出口目录的绝对路径 hot: true,//模块热更新 host: ’localhost’,//默认值 也可以改为 127.0.0.1 或者其他 port: 8080, proxy: { ‘/api’: ‘http://localhost:3000’//请求到 /api/users 现在会被代理到请求 http://localhost:3000/api/users } } })接下来加入错误提示以及将生成 HTML 的代码从公共配置( webpack.common.js )拿到这里 因为开发和生产有些许不一样,我又不知道怎样简单配置,所以开发环境和生产环境我都会放一个生成 HTML 的代码生产环境每次打包都要清理掉旧文件所有代码都要进行压缩重复的 js 代码,需要只有一个就好文件清理从公共配置( webpack.common.js )将之前文件清理的代码拿过来放到这里const merge = require(‘webpack-merge’);const common = require(’./webpack.common.js’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);module.exports = merge(common, { mode: ‘production’, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘2048’, template: ‘./src/index.html’, minify: true,//HTML 代码压缩 hash: true }), ],})代码压缩先安装压缩代码的插件npm install uglifyjs-webpack-plugin -D npm install optimize-css-assets-webpack-plugin -D uglifyjs-webpack-plugin 是 js 压缩插件optimize-css-assets-webpack-plugin 是推荐和const UglifyJsPlugin = require(“uglifyjs-webpack-plugin”);const OptimizeCSSAssetsPlugin = require(“optimize-css-assets-webpack-plugin”);复用代码分离假设需要使用 jQuery 来辅助开发,我在 a.js b.js 两个文件都引入了 jQuery ,将 a.js b.js 打包成 a.min.js b.min.js ,这时看他们的体积会比原来大很多,且 a 和 b 的代码中都包含完整的 jQuery 代码为了解决这种情况,我们需要将 jQuery 这种复用的代码分离到单独的文件在将环境设置为生产环境时默认开启了很多功能,其中 SplitChunksPlugin 就是用于避免重复依赖的在我们不配置时 默认配置是这样的 optimization: { splitChunks: { chunks: ‘async’, minSize: 30000, minChunks: 1, } }chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为async 改成 all 支持所有的minSize: 这个文件最少是多少才去优化,默认为 30000 实际测试是文件大于 30 kb,在 31kb时开始优化minChunks: 最少引用几次才去优化,默认为1 实际测试为在只引用一次的情况不优化,只有大于它才优化注: 还有其他属性个人感觉不常用就没写,了解更多可以看这里最终代码汇总最终公共配置 webpack.common.js 代码如下const path = require(‘path’);const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);module.exports = { entry: { 512:’./src/js/512.js’, 1024:’./src/js/1024.js’, 2048:’./src/js/2048.js’, }, plugins: [ new MiniCssExtractPlugin({ filename: “css/[name].css” }) ], output: { filename: “js/[name].js”, path: path.resolve(__dirname, ‘dist’) }, module: { rules: [ { test: /.js$/, exclude: /(node_modules|bower_components)/, use: { loader: ‘babel-loader’, options: { presets: [’@babel/preset-env’] } } }, { test: /.scss$/, use: [ MiniCssExtractPlugin.loader, ‘css-loader’, ‘postcss-loader’, ‘sass-loader’, ] }, { test: /.(png|svg|jpg|gif)$/, use: [ ‘file-loader’ ] }, { test: /.(woff|woff2|eot|ttf|otf)$/, use: [ ‘file-loader’ ] }, { test: /.(csv|tsv)$/, use: [ ‘csv-loader’ ] }, { test: /.xml$/, use: [ ‘xml-loader’ ] } ] },}最终开发环境 webpack.dev.js 代码如下const merge = require(‘webpack-merge’);const common = require(’./webpack.common.js’);const path = require(‘path’);const webpack = require(‘webpack’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’); module.exports = merge(common, { mode: ‘development’, plugins: [ new HtmlWebpackPlugin({ title: ‘2048’, template: ‘./src/index.html’, minify: false, hash: true }), new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin() ], devtool: ‘inline-source-map’, devServer: { contentBase: path.join(__dirname, ‘dist’), hot: true, host: ’localhost’, port: 8080, proxy: { ‘/api’: ‘http://localhost:3000’ } } })最终生产环境 webpack.prod.js 代码如下const merge = require(‘webpack-merge’);const common = require(’./webpack.common.js’);const UglifyJsPlugin = require(“uglifyjs-webpack-plugin”);const OptimizeCSSAssetsPlugin = require(“optimize-css-assets-webpack-plugin”);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);module.exports = merge(common, { mode: ‘production’, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘2048’, template: ‘./src/index.html’, minify: true, hash: true }), ], optimization: { splitChunks: { chunks: ‘all’ }, minimizer: [ new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true }), new OptimizeCSSAssetsPlugin({}) ], }});npm 项目配置代码 package.json 代码如下{ “name”: “2048”, “version”: “1.0.0”, “description”: “”, “private”: true, “main”: “index.js”, “scripts”: { “dev”: “webpack-dev-server –open –config webpack.dev.js”, “build”: “webpack –config webpack.prod.js” }, “keywords”: [], “author”: “”, “license”: “ISC”, “dependencies”: { “webpack”: “^4.28.3” }, “devDependencies”: { “@babel/core”: “^7.2.2”, “@babel/preset-env”: “^7.2.3”, “autoprefixer”: “^9.4.3”, “babel-loader”: “^8.0.4”, “clean-webpack-plugin”: “^1.0.0”, “css-loader”: “^2.1.0”, “csv-loader”: “^3.0.2”, “extract-text-webpack-plugin”: “^4.0.0-beta.0”, “file-loader”: “^3.0.1”, “html-webpack-plugin”: “^3.2.0”, “mini-css-extract-plugin”: “^0.5.0”, “node-sass”: “^4.11.0”, “optimize-css-assets-webpack-plugin”: “^5.0.1”, “postcss”: “^7.0.7”, “postcss-loader”: “^3.0.0”, “sass-loader”: “^7.1.0”, “style-loader”: “^0.23.1”, “uglifyjs-webpack-plugin”: “^2.1.1”, “webpack-cli”: “^3.1.2”, “webpack-dev-server”: “^3.1.14”, “webpack-merge”: “^4.1.5”, “xml-loader”: “^1.2.1” }} ...

January 3, 2019 · 3 min · jiezi

Vue全家桶 + webpack 构建单页应用初体验

文章指南主题 承接这上一篇Vue + Webpack 构建模块化开发框架详解,我们知道了如何使用webpack对vue进行打包,从而开始我们的前端模块化开发之路,这一篇在上一篇的基础上讲解 Vue全家桶(vue+vuex+vue-router+axios) + webpack 构建一个单页应用Demo前提 阅读本篇内容之前,除了需要掌握上一篇内容中的前提部分的知识,还需要了解以下内容????Vue全家桶系列,掌握vuex,vue-router以及axios ,不了解请移步官方教程axios-npm,vuex,vue-routervue全家桶简单介绍vuex : vuex是一种集中式状态管理模式,什么意思呢?我们在模块化开发过程中,我们以组件来作为模块单位,模块之间存在于不同的命名空间,作用域互不干预,这样保证了我们模块之间变量函数名称等不会冲突,但是有时候我们我们需要组件之间共享一些数据或者状态,我们通常的做法是传参,但是传参的做法至少有两个弊端,一是麻烦(尤其是当需要传递的参数很多时),二是不好管理且冗余(给多个组件传参就需要多份参数列表,而且容易出错)。vuex提供的集中式管理就解决了这个问题,通过把要共享的数据或状态集中起来管理,别的组件需要时就去访问变更,大大提高了可维护性和开发效率vue-router : vue-router是一个前端路由管理器,这个和后端常听说的路由有些不同(个人觉得),这里的路由管理器更像是一个组件注册器,vue-router为分散的组件注册一个路由或者叫地址也未尝不可,以方便我们控制组件的层级嵌套关系以及隐藏还是显示,这样我们可以很方便高效的构建单页应用axios : axios 和 jquery.ajax/vue-resource一样 , 都是HTTP异步请求的工具,axios和vue-resource的API很像,但是个人觉得,axios的API更丰富一些正文 本文的小Demo大概功能就是一个登陆的功能,我们这里app.vue封装了一个登陆组件,success.vue封装了一个提示面板,通过vuex来集中管理登陆状态,用vue-router来路由提示面板,用axios来异步提交到一个跨域的服务器(这里后台服务是nginx+php提供,所以在dev-server中要设置一个反向代理,也就是nginx来代理我们的dev-server的请求从而解决axios跨域问题)先来看看我们的项目结构 [自定义的]这里的目录设置,并不是一成不变的金科玉律,也不一定是最好的,读者可以根据自己的想法设定文件结构,了解如何配置单入口单出口的webpack.config.js,可以看我的上一篇文章(开头提到了),或者移步webpack官方网站。本篇内容,不再讲解过多webpack配置,和上一篇是基本相同的,下面主要讲解 Vue全家桶相关内容index.jsimport Vue from ‘vue’;import Router from ‘./routers/index-router’;import Store from ‘./stores/index-store’;import App from ‘./components/App.vue’;var app = new Vue({ //创建一个Vue实例 router : Router, //加入路由配置 store : Store, //加入状态管理 components : {App} //加入App组件}).$mount(’#app’); //挂载节点需要注意的是,路由和状态都需要加入一个vue实例中去才有意义。这里有一点很有意思,就是在路由router中注册的组件(success.vue)依然可以访问到状态store实例,而官方教程上并没有特别强调这一点,在下面我们可以看到这个有趣的事情stores/index-store.jsimport Vuex from ‘vuex’;import Vue from ‘vue’;import axios from ‘axios’;Vue.use(Vuex); //在vue中加入Vuex插件const Store = new Vuex.Store({ //实例化一个Store state : { //这里是我们需要集中管理的登陆状态 account : “ads”, password : “123456”, islogin : null }, mutations : { // 这是唯一可以变更state的途径,需要通过一个提交 updateAccount(state,payload){ //具有载荷的mutation state.account = payload.account }, updatePassword(state,payload){ state.password = payload.password }, islogin(state,payload){ if(payload == 1){ state.islogin = true }else if(payload == 0){ state.islogin = false } } }, actions : { //这是可以支持异步执行提交的actions login (context,payload){ //这里是去访问我们的反向代理服务器上的一个php文件 axios.get(’/index.php’,{ params : { account : payload.account, password : payload.password } }).then(function(response){ if(response.data.code == ‘success’){ //变更store状态 context.commit(‘islogin’,1) //这里做了在异步逻辑中的状态提交 }else{ context.commit(‘islogin’,0) } }).catch(function(error){ console.log(error) alert(‘fail’) }) } }})export default Store我们这里的Store有三个属性,state是我们需要集中管理的状态或者数据, mutations是维护变更我们状态的一个方式, actions是为了在异步逻辑中提交状态的一个中转站,需要注意的是:在实例化Store之前,必须先 Vue.use(Vuex) ,先在vue中加入Vuex插件这里需要说一下的是,如何开启dev-server的proxy,让nginx来代理axios的请求,也就是跨域访问了(因为dev-server跑的是8080端口,nginx跑的是80端口,不设置代理的话浏览器将拒绝跨域访问),感觉很深奥,其实很简单,我们需要修改一下webpack.config.js中devServer的配置 : webpack.config.js devServer : { contentBase : ‘./dist’, watchContentBase : true, compress : true, port : 8080, hot : true, inline : true, //开启页面自动刷新 open : true, proxy : { ‘/index.php’ : { target : ‘http://localhost:80/phpinfo.php’, secure : false } } }然后,我们的axios在配置url时使用 /index.php,就可以相当于访问http://localhost:80/phpinfo.phprouters/index-router.jsimport VueRouter from ‘vue-router’;import Vue from ‘vue’;import success from ‘../components/success.vue’;// 组件注册路由,这里success组件注册路由是’/app’var routes = [ { path : ‘/app’,component : success }]Vue.use(VueRouter); //在vue中加入VueRouter插件var Router = new VueRouter({ //实例化一个router routes //这里的写法相当于 routes:routes})export default Router;这里的路由只注册了一个组件,vue-router的能力远不止如此,还可以嵌套定义组件的层级关系,更多到官方文档了解 ,路由器和状态管理器一样都是vue官方核心插件,使用前都需要先 Vue.use(VueRouter) ,我们其实可以看到,这里把路由和状态分别从vue实例中抽离出来,单独管理,通过暴露实例Store Router,加入到vue实例中去,这样可以方便debug和后期维护components/App.vue 和 components/success.vueApp.vue<template> <div> <input type=“text” v-model=“account”> <input type=“password” v-model=“password”> <button type=“button” @click=“login”>show</button> </div></template><script> export default { data : function(){ return { account : “”, password : "" } }, created : function(){ this.account = this.$store.state.account this.password = this.$store.state.password }, watch : { //侦听属性 account : function(){ //当accout改变就立即提交状态 this.$store.commit(‘updateAccount’,{ account : this.account }) }, // 当password改变就立即提交状态 password : function(){ this.$store.commit(‘updatePassword’,{ password : this.password }) } }, methods : { login : function(){ //通过分发到action,来异步请求登录服务,并变更状态 this.$store.dispatch(’login’,{ account : this.account, password : this.password }) this.$router.push(’/app’);//同时显示登陆状态 } } }</script><style scoped> input { height: 40px; width: 300px; border: 1px solid blue; box-shadow: none; }</style>success.vue<template> <div> <p>{{islogin}}</p> </div></template><script> export default { computed : { //计算属性 //动态响应状态的变更 islogin : function(){ var islogin = this.$store.state.islogin if(islogin == null){ return ‘No option’ }else if(islogin == true){ return ‘Login Success’ }else if(islogin == false){ return ‘Login Fail’ } } } }</script><style scoped> p { height: 40px; text-align: center; }</style>templates/index.html<!DOCTYPE html><html><head> <meta charset=“utf-8”> <title>index</title></head><body> <div id=“app”> <!– App组件渲染出口 –> <App></App> <!– 注册路由的组件渲染出口 –> <router-view></router-view> </div></body></html>总结好了,到此为止,代码基本完成,我们来理一理,vue+vuex+vue-router以及组件之间是如何配合工作的?用户在App.vue组件中输入,v-model双向绑定了App组件中的data,App组件中的侦听属性发现data改动,立即向vuex的Store实例提交了状态变更,当用户点击show,App组件中methods.login事件被触发,它向Store实例发起一个分发,并导航到/app,Store的action收到分发调用axios去异步请求位于localhost:80下的php后台服务,得到的登陆状态立即提交,与此同时,Router去渲染/app路由对应的组件到模板中去,于是我们就可以看到一个动态响应式的状态提示了 ...

December 19, 2018 · 2 min · jiezi

还不打算去认识一下webpack?

前言随我来,去看看webpack!(为时未晚)============》第一版(较浅显的知识,懂得可忽略本文)方向安装,起步搭建运行. (粗略代过)对于资源的管理,对于输出的管理. (举例介绍)本地开发 (基础服务)热更新=[模块热替换] (初步认识)1.初步构建mkdir webpack_demo && cd webpack_demo // 新建一个文件 并进入更目录 mkdir 是linux命令npm init -y // 初始一个packjage.json文件 -y 表示跳过询问步骤…//安装webpacknpm install webpack –save-dev // 添加webpack-cli依赖到"devDependencies"//webpack4.0+ 需要安装webpack-cli npm install webpack-cli –save-dev // 添加webpack-cli依赖到"devDependencies" //生成如下目录├── package.json ├── src //源目录(输入目录)│ ├── index.js ├── dist // 输出目录│ ├── index.html // 修改 dist/index.html< !DOCTYPE html><html lang=“en”> <head> <meta charset=“UTF-8”> <title>webpack_demo</title> </head> <body> <script src=“main.js”></script> //为什么是main.js下面会解释 </body></html>//修改src/index.js function component() { var element = document.createElement(‘div’); element.innerHTML = “整一个盒子” return element; } document.body.appendChild(component()); npx webpack (Node 8.2+ 版本提供的 npx 命令) node node_modules/.bin/webpack (8.2-版本)会将我们的脚本作为入口起点,然后 输出 为 main.js.打开dist/index.html 你将会看到 整一个盒子 几个字样~2.资源管理,输出管理.基本开发起步//生成如下目录 ├── package.json + |── webpack.config.js //webpack配置文件 ├── src //源目录(输入目录) │ ├── index.js ├── dist // 输出目录 │ ├── index.html 先介绍一个Lodash库 它是一个一致性、模块化、高性能的 JavaScript 实用工具库 模块化处理非常适合值操作和检测(说白了就是webpack用了我也试试…) lodash相关文档npm install lodash –save //非仅在开发的时候使用的依赖 就是需要打包到生产环境的包 不加-dev// src/index.jsimport _ from ’lodash’;function component() { var element = document.createElement(‘div’); element.innerHTML = _.join([’lodash’,‘webpack’],’’); //join将 array 中的所有元素转换为由’‘分隔的字符串 其它函数可以自己实践 return element; }打开index页面输出 loadshwebpack//webpack.config.js const path = require(‘path’); module.exports = { entry: ‘./src/index.js’, //入口 output: { //出口 filename: ‘main.js’, //打包之后脚本文件名称 path: path.resolve(__dirname, ‘dist’) //路径指向执行 js 文件的绝对路径 此处为/dist } };执行npx webpack –config webpack.config.js (把之前dist目录下main.js删除) 新的脚本生成(其实没多大变化..)// 配置一下package.json “scripts”: { “test”: “echo "Error: no test specified" && exit 1”, “build”: “webpack” //添加此行命令 下次执行打包就是 npm run build 相当于上面的npx webpack –config webpack.config.js },// 资源的配置 css 图片 js等等.. 举例 css 图片npm install –save-dev style-loader css-loader css的loadernpm install –save-dev file-loader file(图片)对象的 loader //生成如下目录 ├── package.json + |── webpack.config.js //webpack配置文件 ├── src //源目录(输入目录) │ ├── index.js + │ ├── index.css + │ ├── icon.jpg ├── dist // 输出目录 │ ├── index.html //修改webpack.config.js const path = require(‘path’); //path路径模块 module.exports = { entry: ‘./src/index.js’, //入口 output: { //出口 filename: ‘main.js’, path: path.resolve(__dirname, ‘dist’) }, module: { rules: [ { test: /.css$/, //检测正则匹配.css结尾的文件 use: [ //使用俩个loader ‘style-loader’, ‘css-loader’ ] }, { test: /.(png|svg|jpg|gif)$/, //正则匹配.png svg jpg gif结尾的文件 use: [ //使用file-loader ‘file-loader’ ] } ] } }; //修改src/index.css div{ color:red; } //修改src/index.js import _ from ’lodash’; import “./index.css”; import Icon from ‘./icon.jpg’; function component() { var element = document.createElement(‘div’); element.innerHTML = _.join([’loadsh’, ‘webpack’], ’ ‘); var myIcon = new Image(); myIcon.src = Icon; element.appendChild(myIcon); return element; } document.body.appendChild(component());npm run build(删除之前的dist目录下main.js) 你会看红字和图片 以上就是资源管理的简短介绍npm install –save-dev html-webpack-plugin 安装html-webpack-plugin模块 模块用到功能: 1: 动态添加每次compile后 js css 的hash 2: 可配置多页面 单页面 这些 3: 其它没涉及到npm install clean-webpack-plugin –save-dev 清除dist文件夹(每次删除麻烦了..)配置一下//修改目录 ├── package.json |── webpack.config.js //webpack配置文件 ├── src //源目录(输入目录) + │ ├── app.js + │ ├── print.js │ ├── index.css │ ├── icon.jpg ├── dist // 输出目录 │ ├── index.html //webpack.config.js ===============================================const path = require(‘path’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);module.exports = { entry: { app: ‘./src/index.js’, print: ‘./src/print.js’ }, output: { filename: ‘[name].bundle.js’, path: path.resolve(__dirname, ‘dist’) }, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘webpack_demo’ }) ], module: { rules: [ { test: /.css$/, use: [ ‘style-loader’, ‘css-loader’ ] }, { test: /.(png|svg|jpg|gif)$/, use: [ ‘file-loader’ ] } ] }};//修改src/index.js =================================================== import _ from ’lodash’; //引入lodash模块 import “./index.css”; // index.css import Icon from ‘./icon.jpg’; // 图片 import printMe from “./print.js” // printJS function component() { var element = document.createElement(‘div’); //创建一个元素 element.innerHTML = .join([’loadsh’, ‘webpack’], ’ ‘); // lodash中.join方法 var myIcon = new Image(); //创建一个图片 myIcon.src = Icon; //src赋值 element.appendChild(myIcon); //追加图片 var btn = document.createElement(‘button’); //创建按钮 btn.innerHTML = ‘Click me and check the console!’; //内容赋值 btn.onclick = printMe; //添加事件 element.appendChild(btn); //追加元素 return element; } document.body.appendChild(component()); //追加元素到body中 //修改src/print.js ========================================== export default function printMe() { console.log(‘from print.js’); } npm run build 会发现基本webpack的配置之后 ,有点模样(意思)了 打开页面index.html正常访问3.本地开发npm install –save-dev webpack-dev-server “webpack-dev-server” 为你提供了一个简单的 web 服务器,并且能够实时重新加载 //修改webpack.config.jsconst path = require(‘path’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);const webpack = require(‘webpack’);module.exports = { entry: { app: ‘./src/index.js’ }, output: { filename: ‘[name].bundle.js’, path: path.resolve(__dirname, ‘dist’) }, devServer: { contentBase: ‘./dist’ }, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘webpack_demo’ }) ], module: { rules: [ { test: /.css$/, use: [ ‘style-loader’, ‘css-loader’ ] }, { test: /.(png|svg|jpg|gif)$/, use: [ ‘file-loader’ ] } ] }};//修改package.json…“scripts”: { “test”: “echo "Error: no test specified" && exit 1”, “start”: “webpack-dev-server –open”, //start命令 “build”: “webpack” }, … npm run start 本地起了8080端口的服务,你也可以看到自己的页面4.热更新//修改webpack.config.jsconst path = require(‘path’);const HtmlWebpackPlugin = require(‘html-webpack-plugin’);const CleanWebpackPlugin = require(‘clean-webpack-plugin’);const webpack = require(‘webpack’);module.exports = { entry: { app: ‘./src/index.js’ }, output: { filename: ‘[name].bundle.js’, path: path.resolve(__dirname, ‘dist’) }, devServer: { contentBase: ‘./dist’, hot: true }, plugins: [ new CleanWebpackPlugin([‘dist’]), new HtmlWebpackPlugin({ title: ‘webpack_demo’ }), new webpack.NamedModulesPlugin(), new webpack.HotModuleReplacementPlugin() ], module: { rules: [ { test: /.css$/, use: [ ‘style-loader’, ‘css-loader’ ] }, { test: /.(png|svg|jpg|gif)$/, use: [ ‘file-loader’ ] } ] }}; npm run start 运行http://localhost:8080/ 然后你去修改print js的console(或者添加其他代码) 会发现命令行输出updated. Recompiling… 字样 这就是简单的实现了热更新最后本文只是大概从几个demo来对于webpack的基础概念 入口entry 出口 output loader plugins mode(没有直面涉及)几大模块的梳理于实践,让大家对于webpack不在那么陌生!后续文章会从更深入的角度去学习webpack! 暂定下周1 发表文章(内容 详细介绍hot 实现一个简易的vue-cli等等)demo的代码我会同步github ...

November 6, 2018 · 4 min · jiezi