工程化 -- Webpack

工程化,简单来说就是使小作坊生产变成流水线生产,实现自动化、模块化、性能优化等。

自动化可以通过命令行来实现。

实现从SCSS到CSS的自动化

  1. 全局安装Node-sass node-sass
    npm install -g node-sass
    (事实上SASS是Ruby社区写的)
  2. 为了演示实现过程,我先把目录已有的一个style.css后缀改成style.scss
    mv style.css style.scss
    这样直接改后缀是没有问题的,因为SCSS是完全兼容CSS的,它只是在CSS语法上加上一些更高级的用法。
  3. 现在可以用node-sass把SCSS翻译成CSS了
    node-sass style.scss style.css
    实际上现在只是将排版变得漂亮了一点,因为我们并没有改SCSS的内容。
  4. 在style.scss写一些新语法,例如:
.topNavBar{
        nav {
            padding-top: 5px;
            > ul {
                list-style: none;
                margin: 0;
                padding: 0;
                > li {
                    float: left;
                    margin-left: 17px;
                    margin-right: 17px;
                    position: relative;
                    > a {
                        font-size: 12px;
                        color: inherit;
                        font-weight: bold;
                        border-top: 3px solid transparent;
                        border-bottom: 3px solid transparent;
                        padding-top: 5px;
                        padding-bottom: 5px;
                        display: block;
                        position: relative;
                    }
                }
            }
        }
    }
  1. 再次运行命令 node-sass style.scss style.css,可以看到style.css里对应内容已经被翻译成CSS语法:
.topNavBar nav {
  padding-top: 5px; }
  .topNavBar nav > ul {
    list-style: none;
    margin: 0;
    padding: 0; }
    .topNavBar nav > ul > li {
      float: left;
      margin-left: 17px;
      margin-right: 17px;
      position: relative; }
      .topNavBar nav > ul > li > a {
        font-size: 12px;
        color: inherit;
        font-weight: bold;
        border-top: 3px solid transparent;
        border-bottom: 3px solid transparent;
        padding-top: 5px;
        padding-bottom: 5px;
        display: block;
        position: relative; }
  1. 由于不能直接引入style.scss,现在每次改style.scss都要执行一次命令将其翻译成CSS语法,这样写岂不是很傻?
  2. 使用-w监听style.scss的变动,每次style.scss有改动都自动翻译
    node-sass style.scss style.css -w

如此就实现了从SCSS到CSS的自动化。

Babel自动将下一代JS代码变成浏览器兼容的JS代码

  1. 我在写JS的时候已经用到了很多新的语法,当把代码下发给很多用户时,总会有不兼容的浏览器,比如IE。我需要将使用了新语法代码变为浏览器兼容的代码
  2. Babel命令行可以实现这个需求。
  3. 安装Babel
    npm install --save-dev babel-cli
    安装之前应该有package.json,如果没有,新建一个。
    npm init可以创建一个合法的package.json
    安装完成后检查一下package.json,如果多出下面代码,说明已经成功将Babel安装到项目中了。
{
  "devDependencies": {
+   "babel-cli": "^6.0.0"
  }
}
  1. 在package.json里加代码:(如果有上一句,记得写逗号)
 {
    "name": "my-project",
    "version": "1.0.0",
+   "scripts": {
+     "build": "babel src -d lib"
+   },
    "devDependencies": {
      "babel-cli": "^6.0.0"
    }
  }
  1. 根据文档运行npm run build,报错。
    为什么呢?因为运行npm run build就是在运行前面加的代码babel src -d lib,也就是运行npm run build和直接运行babel src -d lib没有任何区别。而我们的Babel是局部安装的,安装在./node_modules/.bin/babel,路径没有写全当然会报错。
    运行./node_modules/.bin/babel src -d lib相当于第4步npm在scripts里加入的一句代码,反过来说,当npm运行第4步所加的这句话的时候会优先认为babel是./node_modules/.bin/babel,会优先找这个路径。
    命令行的实质就是文件,全局安装和项目安装的区别看这里
  2. babel src -d lib的意思是把src目录的JS全部翻译成兼容浏览器的JS,放在lib目录里。d,destination。命令行基础要扎实,从一个字母猜到它的意思。
    例如,运行./node_modules/.bin/babel js -d dist,将js目录里的文件翻译到dist目录里
  3. 页面中要引入/js的地方路径改为/dist,也就是引入dist里面的js,而不是js里面的js
  4. 我们又遇到了跟上文写SASS一样的问题,每次改写js都要再执行一次命令,很傻。babel也提供了跟SASS一样的命令,让它自动翻译:./node_modules/.bin/babel js -d dist --watch

整理代码

按照前端一般的规范,项目里有两个大目录,src(source)放未经翻译的代码,dist(distribution)放待发布代码。如果有第三方代码,放在node_modules里。

把所有html,SCSS,js,包括img都放进src中。
mkdir src
mkdir src/css
mv *.html src/
mv *.scss src/css
mv js/ src/
mv img src/
现在src目录中包含一个首页、一个css目录、一个js目录、一个img目录,整齐多了。(整理完要改引入文件的路径)
虽然整齐了,但是现在代码不能运行了,必须要做翻译。

进程1:
先用node-sass将src/css/翻译到dist/css/并监听,输出到一个目录里要用-o
node-sass src/css -o dist/css -w

进程2:
再用Babel将src/js/翻译到dist/js/并监听
./node_modules/.bin/babel src/js/ -d dist/js/ --watch

进程3,进程4:
此外,index.html和img目录也需要被监听,每次有变化就拷贝到dist目录,这又需要两个进程。watch-cli

以上所实现的自动化,是因为前端比较分裂,有人喜欢写css,有人喜欢写sass;有人喜欢写ES5的JS,有人喜欢写ES6的JS,等等。用翻译工具把它们自动翻译成兼容浏览器的代码,就是自动化。

如果有更复杂的需求,比如dist发布时加版本号,一旦有需求自动改版本号,则需要开更多的进程。请看Cache-Control 如何更新缓存

这一大堆进程可以用一个工具实现,一开始是Grunt,后来被更快的Gulp替代,再后来又被Webpack替代。

配置Webpack

webpack github

  1. 在一个安全的目录中演示
    mkdir webpack-demo
    cd webpack-demo
    npm init -y
    npm install webpack@3 webpack-cli --save-dev 演示webpack3
    现在可以看到package.json中多了一条依赖:
"devDependencies": {
    "webpack": "^3.12.0",
    "webpack-cli": "^3.0.1"
}
  1. 创建配置文件 touch webpack.config.js
  2. src/index.js输出为dist/bundle.js,创建演示需要的目录和文件
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};
  1. 试一下,在index.js里写入
let a = 1
console.log(a)

执行命令npx webpacknode_modules/.bin/webpack
可以看到当前目录里出现了dist/bundle.js,可以在这个文件中找到index.js里的代码,现在webpack可以做简单的JS拷贝工作了。

  1. 继续写配置,让JS兼容浏览器,让let变成var
    babel-loader 7.x
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env']
        }
      }
    }
  ]
}

再次运行npx webpack,报错,找不到什么就npm install 找不到的东西
如果是找不到envnpm install @babel/preset-env
运行成功后,dist/bundle.js中的let已经变成var

  1. 使用模块化
    在当前目录下src/js目录里创建module-1.js,module-2.js和app.js三个文件:
//module-1.js
function fn(){
    console.log(1)
}
export default fn  //如果有人引用module-1.js,就默认把fn传给他
//module-2.js
function fn(){
    console.log(2)
}
export default fn
//app.js
import x from './module-1'
import y from './module-2' //x,y就是module-1,module-2返回的fn

x()
y()

然后只需要把app.js翻译成浏览器兼容的JS即可。更改webpack配置,把src/js中的三个JS文件翻译到dist/js/bundle.js中:

const path = require('path');

module.exports = {
  entry: './src/js/app.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist/js')
  }
};

再次运行./node_modules/.bin/webpack,可以看到结果三个文件输出到了一个文件中:

bundle.js  3.27 kB       0  [emitted]  main
   [0] ./src/js/app.js 343 bytes {0} [built]
   [1] ./src/js/module-1.js 141 bytes {0} [built]
   [2] ./src/js/module-2.js 141 bytes {0} [built]

页面中只需要引入一个bundle.js就可以了。
这样就实现了JS的模块化有JS自己来控制,而不是在html里面控制。

  1. sass-loader把SCSS翻译成CSS:
    安装sass-loader:npm install sass-loader node-sass webpack --save-dev
    安装style-loader和css-loader:npm install style-loader css-loader --save-dev
    写配置:
 module: {
        rules: [
        {......}, //前面已有的配置
        {
            test: /\.scss$/,
            use: [ //从下往上
                "style-loader", // 用JS字符串创建style节点
                "css-loader", // translates CSS into CommonJS 把css变成字符串
                "sass-loader" // 把sass编译成css
            ]
        }]
}

模块化:把src/css/main.scss加载到dist/js/bundle.js中变成一个字符串,等bundle.js运行的时候把这个字符串放到页面里的style标签里。(css可以用字符串的形式存储,例如皮卡丘)

// src/js/app.js
import x from './module-1.js'
import y from './module-2.js'
import '../css/main.scss' //css也从这里引入

x()
y()
  1. 自动加前缀 postcss-loader
    安装postcss-loader npm i -D postcss-loader
    新建postcss.config.js写配置:touch postcss.config.js
module.exports = {
  //parser: 'sugarss',
  plugins: {
    'postcss-import': {},
    'postcss-cssnext': {},
    'cssnano': {}
  }
}

写webpack.config.js:

 use: [
    "style-loader", 
    "css-loader", 
    "postcss-loader", //必须写在style-loader和css-loader之后,其他之前
    "sass-loader" 
]

再运行./node_modules/.bin/webpack,看报错,找不到什么就安装什么。

本文代码

webpack每次需要实现一个功能都需要写配置,很不方便。可以使用不需要写配置的parcel代替它。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容