例如,我们新建一个main.js 用于整合js,在这里面引其他的文件,通过main.js 自动把其他js加载进来
- node模块的规范是commonjs,这个规范定义了:如何引用、如何导出、如何定义
- 除了commonjs规范外,前端也有一些规范:cmd(seajs-define) / amd(requirejs引入一些模块),这些都是一些规范
- 为什么出现cmd/amd这些规范,因为以前前端不支持模块化,但是现在es6已经兼容了模块化(esmodule–es的模块),我们可以基于es6来使用一些模块了
问题: seajs
、 requirejs
、esmodule
和 commonjs
的区别?
seajs
和 requirejs
:seajs
和 requirejs
是人家写好的规定的写法;seajs
和 requirejs
是一个帮我们实现模块化的库,还需要引用这个库commonjs
:commonjs
是node
的规范,只能在编辑器里右键 run,不能直接在浏览器里运行;而import不能在编辑器里右键runlet a = require('../')
这种写法是node
的写法,不能再前端使用,而且前端也没有require
这个关键字,会报错require is not defined
在commonjs中/也就是在nodejs中,
1. 定义模块:一个js文件就是一个模块;
2. 导出模块:exports 或者 module.exports
3. 引入模块:require
esmodule
:关于esmodule:
1. 定义模块:一个js就是一个模块
2.导出模块: export (注意es6 没有s)
3.引入模块:import
es6
的模块化可以在浏览器中用
注:umd – 用来兼容处理,用了它之后可以既支持cmd 又支持amd 又支持commonjs规范
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script src='main.js' type='module'>script>
body>
html>
//要在main.js里引入这两个变量,这里要先导出变量
export let str1 = '这是a.js里的变量1';
export let str2 = '这是a.js里的变量2';
/*
这些写的实现:会将str1 和 str2放到一个对象里导出,然后在main.js里引入
{str1:'这是a.js里的变量1',str2:'这是a.js里的变量2'}
*/
/*
node的commonjs规范的写法是:
exports.str1 = str1;
exports.str2 = str2;
//最后导出exports对象
*/
// 导出方法/函数
export function a(){
console.log('a方法');
}
//导出箭头函数
export let c = ()=>{
console.log('c方法');
}
// 默认导出:可以是变量 对象 方法都可以
export default {
m:999,
n:'你好'
}
//let a = 'c.js里的默认导出';
//export default a;
./
;如果是文件模块(自己写的js)需要加 ./
//通过main.js来引其他的js
/*
import './a.js';
//这里 .js 可以省略,这只是引入了js,但是要直接在这个js文件用a.js里的导出,需要放到变量上;
//let a = require('./a.js'); //就像这里的commonjs写法,commonjs里的写法,带有变量a
*/
// -----------------------
console.log(str1); //import 具有提升效果,可以预解析;可以在import前拿到;
import {str1,a as b,c} from './a.js';
// a.js里会将str1 和 str2放到一个对象里导出,所以这里引入的时候,应该放一个 对象 和 a.js 相匹配
// 这样的写法用到了 解构赋值:在另一个文件中将内容结构出来即可使用
// import a from './a.js'; //这样写需要在 a.js里写一个名字是default的导出,作为默认导出
console.log(str1);
b(); //引入的方法名要和导出的一样,可用as 修改命名
c();
//问题1:上面的写法很复杂,要导出的变量很多时很麻烦;
//注意1:而且 import {str1} from './a.js'; 里面的结构赋值 let {str1} = {str1:111};相当于把str1声明过了,下面就不能再声明这个变量了
//import 拥有声明功能,下面就不能再声明和他一样的变量了;
//注意2:import 具有提升效果,可以预解析;可以在import前拿到;但最好import放到顶部;
// ---------------------------------------------
// 作为一个对象引入
import * as d from './b.js';
// * 代表输出的所有的, as b 这样写b就是一个对象了(导出所有的放到* 中,并重命名为d)
console.log(d.str3);
import m from './b.js'; //k 是b.js里 export default后面的内容,后面是个对象,所以k是个对象
console.log(m);
//-------------------------
import xx from './c.js';
console.log(xx);
// esmodule 的要求:1.要求谷歌必须62以上的(而且es6语法,箭头函数什么的解析不了)
/*
我们希望:
1.语法问题,可以把高级语法转成低版本语法,babel 翻译器,可以把es6,es7 翻译成es5
2.模块问题:代码中可能会有import语法,这在低版本浏览器也不认识,我们希望模块 转成闭包 ,webpack--一个打包器
*/
/* webpack 是一个 模块加载器 兼 打包工具(可以把各种资源js,css进行自动编译)
雪碧图还是要发请求,如果图片比较小的,我们希望转成base64,这样就可以不发请求了,都可以用webpack
1. webpack 是基于commonjs的规范来写的,写法是node的写法,但对AMD,cmd 也支持;
2.能被模块化的不仅仅是js(以前模块只针对js文件),webpack也可以支持图片,css,less,sass
3.我们写的代码怕被别人拷走,所以上线的时候打包,混淆压缩;还可以图片转base64等,能替代部分gulp的工作;
4.写代码时以保持,页面就自动更新,不用刷浏览器,刷浏览器很耗性能;
webpack -模块处理器:处理各种依赖关系,天然可以处理模块的问题 */
webpack.config.js页面:
let path = require('path');
//peth是node的内置模块,用来处理路径的;最常用的方法是resolve()
path.resolve('./dist'); //以当前路径解析出一个绝对路径
console.log(path.resolve('./dist'));
//resolve是解析,给他一个相对路径,会返回一个绝对路径;
//webpack 必须采用commonjs的写法,不能用es6或其他的;
// 规定的是要导出一个模块module.exports = {}
module.exports = {
entry:'./src/main.js',
//打包的入口文件,webpack会自动查找相关的依赖进行打包
//在main.js里引了一些其他的js文件
output:{
filename:'bundle.js', //打包后的名字
path:path.resolve('./dist'), //必须是一个绝对路径,打包文件放的位置
// c://xx/xx/index.js 这是绝对路径; ./a/index.js 这是相对路径
// path:__dirname+'/dist', //__dirname 是目录名,是个绝对路径,这样写也可以
}
}
多入口打包,配置webpack.config.js页面:
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
module.exports = {
entry:{ //多文件打包,入口文件放在对象里
main1:'./src/main1.js',
main4:'./src/main2.js'
},
output:{
filename:'[name].js',
//出口的文件,[name]会自动匹配对象里的key的名字
path:path.resolve('./dist'),
}
}
npm install babel-core --save-dev
npm install babel-loader --save-dev
babel-core是babel的核心包,babel-loader 基于babel-core,babel-loader是用来解析语法的;(core相当于转译器,loader是加载器,用来解析语法的)
babel-preset-es2015
做一些预设:让翻译官babel-loader拥有解析es6语法的功能npm install babel-preset-es2015 --save-dev
安装完这个后,会生成很多个小包,以babel-plugin-开头的一些插件
.babelrc
,这这里面写一些预设,在babel-loader编译的时候,会到这个``文件里找,是不是会编译目标语言;{
"presets":["es2015"]
}
注意:是presets,有s
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{
test:/\.js$/,
use:'babel-loader',
exclude:/node_modules/,
}
//用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
//匹配所有.js,用babel-loader转译,排除掉node_modules
]
}
// js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
}
下面的就是es7语法:
let obj1 = {name:'lxz'};
let obj2 = {age:18};
let newObj = {..obj1,..obj2}; //这是es7语法
babel-preset-stage-0
用来解析es7语法,0 包含了所有的,babel-preset-stage-4是es6npm install babel-preset-stage-0 --save-dev
.babelcr
{
"presets":["es2015","stage-0"]
}
之前我们都是在html里引css,如果想在js中引用css,想把css当成模块进行加载;webpack默认只认js,但是可以通过一些手段认识css
import './index.css'
npm install css-loader style-loader --save-dev
解析成css后还得放到html页面上,我们可以通过link标签引进来;也可以通过style标签,把文件写到style标签里,可以用style-loader
css-loader将css解析成模块,style-loader将解析的内容插入到style标签里
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{ // js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
test:/\.js$/, //用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
use:'babel-loader',
exclude:/node_modules/, //匹配所有.js,用babel-loader转译,排除掉node_modules
},{
test:/\.css$/,
use:['style-loader','css-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
}
]
}
}
打包完后,css样式是被打包到bundle.js里;
编译less需要
less-loader , less , css-loader , style-loader
npm install less less-loader --save-dev
less的好处可以写嵌套语法;
2. 配置webpack.config.js文件
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{ // js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
test:/\.js$/, //用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
use:'babel-loader',
exclude:/node_modules/, //匹配所有.js,用babel-loader转译,排除掉node_modules
},{
test:/\.css$/,
use:['style-loader','css-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
}
]
}
}
我们解析图片的时候需要用到url-loader
, url-loader
依赖于file-loader
,所以安装的时候都要安装,用的时候只用url-loader
npm install less file-loader url-loader --save-dev
2.在webpack.config.js里写解析规则
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{ // js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
test:/\.js$/, //用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
use:'babel-loader',
exclude:/node_modules/, //匹配所有.js,用babel-loader转译,排除掉node_modules
},{
test:/\.css$/,
use:['style-loader','css-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.(jpg|png|gif|svg)$/,
use:['url-loader?limit=8192'], // 图片会给转成base64,我们可以限制8k(8*1024=8192字节)一下的转base64,其他情况下输出图片
}
]
}
}
这样解析成的图片会给转成base64,转成字符串base64后,就不会再发请求了
但是我们希望大的图片还是实体文件,小的图片才转base64
在js里引入图片需要import,或者写一个线上路径;
import page from './1/jpg'; //webpack找到依赖的图片1.jpg 进行打包,打包后的路径放在page里
let img = new Image();
img.src = page; //page是打包后图片的路径
// img.src = './1/jpg'; //这样写,webpack会认为这是一个字符串,不会进行查找解析,所以相对的不可以,但是线上的路径本来就是个字符串,是可以正常显示的
document.body.appendChild(img);
html-webpack-plugin
插件的作用:以自己的html为模板,将打包后的结果 自动引入到html中,产出到dist目录下
上面说的loader 是用来解析模块的;这里的插件是用来给webpack加一些新的功能的;
npm install html-webpack-plugin --save-dev
html-webpack-plugin
是个第三方模块(插件),用之前需要自己先引入
他可以帮我们把html输出到dist下,而且自动引入打包的js文件;
在webpack.config.js中:
let HtmlWebpackPlugin = require('html-webpack-plugin');
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{ // js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
test:/\.js$/, //用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
use:'babel-loader',
exclude:/node_modules/, //匹配所有.js,用babel-loader转译,排除掉node_modules
},{
test:/\.css$/,
use:['style-loader','css-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.(jpg|png|gif|svg)$/,
use:['url-loader?limit=8192'], // 图片会给转成base64,我们可以限制8k(8*1024=8192字节)一下的转base64,其他情况下输出图片
}
]
},
plugins:[
new HtmlWebpackPlugin({ //以自己的html为模板,将打包后的结果 自动引入到html中,产出到dist目录下
template:'./src/index.html', //使用的模板:自己定义的模板
filename:'login.html' //产出的文件的名字:可以修改输出到dist下的html的文件名
}),
]
}
我们每次npm run build 都算是读写文件,从src里读然后写到dist里,这是通过node做的;IO读写浪费性能;
我们希望代码上线的时候再产生dist,在开发的时候不用;
所以我们希望在不产生dist下文件的情况下还能看到效果,webpack给我们提供了一个服务webpack-dev-server
,这个服务可以给我们展示代码的效果
webpack-dev-server
里面内置了服务,可以帮我们启动一个端口号,当代码更新时,可以自动打包(在内存中打包,不产生实体文件),而且时刻监控代码,代码有变化就重新执行
npm install webpack-dev-server --save-dev
"scripts": {
"build": "webpack",
"dev":"webpack-dev-server"
},
如上配置,我们npm run build
的时候走的是node_modules下.bin里的webpack.cmd
;–用于放生产前打包
npm run dev
的时候运行的是node_modules下.bin里的webpack-dev-server命令 --用于开发时起服务
运行npm run dev
会帮我们启动一个服务器,打开一个网页,端口号默认8080;默认情况下打开的是index.html
以前在html里用script引js,现在是在js里用import引入js
import Vue from 'vue';
//这样引入vue,引用的并不是vue.js,引用的是vue的runtime.common.js
vue由两部分组成,
vue = compiler(编译用的,compiler可以编译模板) + runtime
‘vue’ 是第三方模块,不用加./,找的时候去node_modules下vue文件夹下的package.json里main对应的文件"main": "dist/vue.runtime.common.js"
第三方模块查找就是通过node_modules下vue文件夹下package.json找main对应的文件
npm install vue-loader vue-template-compiler --save-dev
- vue-loader 用来解析.vue文件的,vue会自动的调用vue-template-compiler
- vue-template-compiler 用来解析vue模块的
let path = require('path');
// path.resolve('./dist'); //以当前路径解析出一个绝对路径
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve('./dist'),
},
// 模块的解析规则
module:{
rules:[
{ // js: 匹配除node_module以外的所有.js后缀的文件,用babel-loader进行转译,转成es5;
test:/\.js$/, //用正则匹配,/\.js$/以.js结尾的,exclude排除掉xx
use:'babel-loader',
exclude:/node_modules/, //匹配所有.js,用babel-loader转译,排除掉node_modules
},{
test:/\.css$/,
use:['style-loader','css-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.less$/,
use:['style-loader','css-loader','less-loader'], // 这里数组里要 从右往左写,先在右边写css-loader,然后写左边style-loader
},{
test:/\.(jpg|png|gif|svg)$/,
use:['url-loader?limit=8192'], // 图片会给转成base64,我们可以限制8k(8*1024=8192字节)一下的转base64,其他情况下输出图片
},{
test:/\.vue$/,
use:['vue-loader'], //vue会自动的调用vue-template-compiler,就不用配vue-template-compiler了
}
]
},
plugins:[
new HtmlWebpackPlugin({ //以自己的html为模板,将打包后的结果 自动引入到html中,产出到dist目录下
template:'./src/index.html', //使用的模板:自己定义的模板
filename:'login.html' //产出的文件的名字:可以修改输出到dist下的html的文件名
}),
]
}
import Vue from 'vue';
//这样引入vue,引用的并不是vue.js,引用的是vue的runtime.common.js
//vue = compiler(编译用的,compiler可以编译模板) + runtime
import App from './App.vue' //自己写的文件模块加./
console.lgo(App); //app 是个组件,组件是一个对象,这个对象可以通过createElement()创建成一个虚拟dom,然后通过render函数将虚拟dom渲染成真实的dom
new Vue({
//createElement() 返回的是虚拟dom
//render函数将虚拟dom渲染成真实的dom
render:function(createElement){ //因为引的是vue.runtime.common.js 没有compiler,所以要用render渲染
return createElement(App);
}
// render:(h)=>h(App) render可以简写成这样
}).$mount('#app') //等价于在配置里写 el:'#app'
vue-loader的作用是把.vue文件变成一个模块