npm+babel+webpack解決不能import問題

引言

當本身從土裏搭建起來一個網站,即便是最原始的那種網站,菜鳥如我也會遇到有許許多多瑣碎又細小的問題。本篇幅記錄關於代碼轉換和代碼打包相關工做。javascript

這兩個問題主要的矛盾在於,以前我一直是用<script>來加載各種css,js,ico等文件的:
本地資源:css

<link="icon" href="http://www.xxxxxxxxx.top/icon/icon.ico">
<link="stylesheet" href="http://www.xxxxxxxxx.top/css/globalStyle.css type="text/css">
<script src="http://www.xxxxxxxxx.top/node_modules/socket.io-client/dist/socket.io.js"></script>

各種cdn:html

<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
    
<script src="https://cdn.bootcss.com/react-router/5.0.1/react-router.min.js"></script>
<script src="https://cdn.bootcss.com/react-router-dom/5.0.1/react-router-dom.min.js"></script>
    
<script src="//cdn.jsdelivr.net/npm/leancloud-storage@3.15.0/dist/av-live-query-min.js"></script>

有一天,有一些cdn崩了,致使網站無法用。我就想npm install到本地吧,而後用import加載各種文件。而後就遇到了各種問題,雖然最後解決方法看起來很簡單,但過程很艱辛、費時間,要是不寫一篇文章總感受時間花的太不值了。一方面給將來的本身查看起來方便,一方面但願能給有幸看到這篇文章的小夥伴們節約點時間。java

babel

由於網站用的React搭建的,Reactjsx語法用起來很開心,但jsx須要翻譯成js官方語法&瀏覽器認識的語法才能使用。React官網推薦使用Babeljsx進行翻譯。因此,那就Babel咯~
react官網-babel-1.pngnode

react官網-babel-2.png

babel是什麼

babel是一個JavaScript 編譯器,它將各種不一樣版本的javascript語言標準翻譯成你想要的版本。意思就是,最新版本的javascript語法,部分版本的瀏覽器不支持,須要轉換成低版本的javascript語法,才能實現兼容。引用Babel官網的話:react

babel官網介紹.png

Babel有這麼幾個主要的概念:Presets、Plugins、Config Files、Cliwebpack

Babel:Plugins

Plugins,插件,是Babel實現功能的主要模塊。經過安裝不一樣的插件,Babel能夠實現不一樣的功能。web

例如:typescript

Plugins的使用,你只須要經過npm install 插件名稱安裝一下,再經過配置文件+cli或者cli使用就ok了shell

Babel:Presets

Presets,預設,就是Babel將各種插件整合在一塊兒,來提供一系列功能。

官方Presets:

  • @babel/preset-env:這個是最新Babel-7版本出的預設,拋棄老版本繁亂的插件,這個預設經過配置能根據瀏覽器版本,將代碼自動翻譯成最適合的版本。
  • @babel/preset-flow:這個我看不太懂
  • @babel/preset-react:這個是專爲React作的預設,能很好的將React簡便寫法翻譯成React正經語法
  • @babel/preset-typescript:這個是轉爲TypeScript作的預設,只包含一個插件

你也能夠本身作一個Presets:

  • 把插件用數組組起來,文件取名myPreset.js

    module.exports = function() {
      return {
        plugins: [
          "pluginA",
          "pluginB",
          "pluginC",
        ]
      };
    }
  • 也能夠引用其它Presets

    module.exports = () => ({
      presets: [
        require("@babel/preset-env"),
      ],
      plugins: [
        [require("@babel/plugin-proposal-class-properties"), { loose: true }],
         require("@babel/plugin-proposal-object-rest-spread"),
      ],
    });
  • 在配置Config Files中引用,npm模塊名或者相對路徑

    {
      "presets": ["babel-preset-myPreset"]
    }
    {
      "presets": ["./myProject/myPreset"]
    }

Presets的使用,你只須要經過npm install 預設名稱安裝一下,再經過配置文件+cli或者cli使用就ok了

Babel:Usage

有不少方式使用Babel,這裏就只介紹兩種,由於我就會這兩種😜

Babel:Usage:Config Files+Cli

經過配置文件能夠配置Babel用什麼插件、用哪一種預設、設置環境變量、忽略某一文件夾等。菜鳥如我簡單用用就設定用什麼插件用哪一種環境變量就好了~

  • npm init的地方,手動新建文件babel.config.json or babel.config.js或者.babelrc.json。關於兩種區別,Babel官網相關部分是這樣描述的:
    babel官網configFiles.png
  • 配置文件內容:
    babel.config.json.babelrc.json

    {
      "presets": ["presetName1","presetName2"],
      "plugins": ["pluginName1","pluginName2"]
    }

    babel.config.js

    module.exports = function (api) {
     api.cache(true);
    
     const presets = [ ... ];
     const plugins = [ ... ];
    
     return {
       presets,
       plugins
     };
    }
  • 接下來是Cli部分,命令行中輸入:

    npx babel -w 原始文件地址/原始文件名 --out-file 輸出文件地址/輸出文件名

    -w表示監聽,--out-file表示後面跟的是輸出文件信息。命令執行後,會自動調用配置文件中的相關配置。

Babel:Usage:Cli

純命令行模式使用

  • 命令行中輸入:

    npx babel script.js --out-dir lib --watch --out-file script-compiled.js --source-maps --ignore "src/**/*.spec.js","src/**/*.test.js" --presets=@babel/preset-env,@babel/flow --plugins=@babel/proposal-class-properties,@babel/transform-modules-amd

其實就是將配置文件中的配置全移到命令行內實現,利用--watch、--presets、--plugins、--ignore、--source-maps等這樣的命令行參數。參數具體含義可參考Babel官網相關內容

webpack

爲何會用到webpack呢?是這樣的。當我使用import加載模塊名的時候,瀏覽器會報錯

加載模塊名:

import {HashRouter,Switch,Link,NavLink,Route,BrowserRouter} from "react-router-dom";

報錯:
Uncaught TypeError: Failed to resolve module specifier "react-router-dom". Relative references must start with either "/", "./", or "../"

當我使用import加載路徑/文件名的時候,瀏覽器會報錯

加載路徑/文件名:

import React from "./node_module/react/index.js";

報錯:
Uncaught TypeError: Failed to resolve module specifier: "react"
export 'default' was not found in "./node_module/react/index.js"

嘛~具體的報錯內容不記得了,反正就是這個意思,瀏覽器老是會報錯。若是使用Babel的智能翻譯預設@babel/preset-env進行翻譯後,Babel會將import都翻譯成require,這樣致使的結果仍是瀏覽器報錯:

翻譯前:

import React from "react";

翻譯後:

var React = require("react");

報錯:
ReferenceError: require is not defined

通過費時的尋找解決方案,我只能經過打包工具對importrequire進行處理。webpack那麼火,那就用webpack吧~

webpack是什麼

webpack就是JavaScript靜態模塊打包器(static module bundler)。它能夠將各種資源import到一塊兒,包括.css、.png、.xml、.js等文件,而後「打包」生成一個新的js文件。新文件僅包含依賴的文件,而且可文件壓縮,還能代碼壓縮。

webpack有這麼幾個主要的概念:Entry、Output、Loaders、Plugins、Mode

Webpack: Usage

webpack的使用很簡單。首先,建立一個配置文件webpack.config.js,而後,執行打包命令npx webpack。這樣就會在你指定的目錄下生成新的js文件,在你的html內引用這個js文件就ok了~

  • 安裝

    npm install webpack webpack-cli --save-dev
  • 建立配置文件

    const path = require('path');
    
    module.exports = {
        entry: 入口文件,
        output: {
            path: 出口文件目錄,
            filename: 出口文件名
        },
        module: {
            rules: [
                各種loader配置項
            ]
        },
        plugins: [各種插件名],
    };
  • 使用

    npx webpack

Webpack:Entry

Entry用於在配置文件中配置打包入口。意思就是從Entry開始,查找全部它的依賴,進行打包。經常使用格式以下:

module.exports = {
  entry: './path/to/my/entry/file.js'
};

Webpack:Output

Output用於在配置文件中配置打包後新文件的位置。經常使用格式以下:

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};

path表示輸出文件的絕對路徑__dirname表示該配置文件所在的絕對路徑,filename表示輸出的新文件名,path.resolve()會將括號內的參數解析成一個完整的路徑、固然用以前須要引入nodejs模塊:const path = require('path');。如上述例子會打包輸出到__dirname/dist/my-first-webpack.bundle.js

Webpack:Loaders

Loaders用以使webpack可以加載打包非js文件。全部的Loaders能夠查看官網。經常使用格式以下:

const path = require('path');

module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'my-first-webpack.bundle.js'
    },
    module: {
        rules: [
            {
                test: 文件名正則,
                use: [
                    "loader-name"
                ]
            }
        ]
    }
};

Webpack:Loaders:css

  • 安裝

    npm install --save-dev style-loader css-loader
  • 修改配置文件

    module: {
     rules: [
       {
         test: /\.css$/,
         use: [
           'style-loader',
           'css-loader'
         ]
       }
     ]
    }
  • 使用

    import './style.css';

Webpack:Loaders:file

file-loader可用來加載圖片或者文字或者其它文件類型。

  • 安裝

    npm install --save-dev file-loader
  • 修改配置文件

    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
       {
         test: /\.(png|svg|jpg|gif)$/,
         use: [
           'file-loader'
         ]
       },
       {
         test: /\.(woff|woff2|eot|ttf|otf)$/,
         use: [
           'file-loader'
         ]
       }
      ]
    }
  • 使用
    入口文件:

    import './style.css';

    style.css:

    @font-face {
        font-family: 'MyFont';
        src:  url('./my-font.woff2') format('woff2'),
              url('./my-font.woff') format('woff');
    }
    
    .hello {
        font-family: 'MyFont';
        background: url('./icon.png');
    }

Webpack:Plugins

Plugins,插件,用於幫助webpack實現各類各樣的功能。以下例子clean-webpack-plugin插件幫助清理文件夾,刪除不須要的依賴文件。

  • 安裝

    npm install clean-webpack-plugin --save-dev
  • 修改配置文件

    const path = require('path');
      const CleanWebpackPlugin = require('clean-webpack-plugin');
    
      module.exports = {
        entry: './path/to/my/entry/file.js',
        plugins: [
          new CleanWebpackPlugin(['dist']),
        ],
        output: {
          path: path.resolve(__dirname, 'dist'),
          filename: '[name].bundle.js',
        }
      };
  • 進行打包命令

Webpack:Mode

mode用來在配置文件中指定環境:development&productionwebpack在不一樣環境下會加載不一樣的插件和處理方式。

  • 修改配置文件

    module.exports = {
       mode: "production",
    }
    module.exports = {
      mode: "development",
    }

總結

個人目標是將<script>標籤儘量多的轉換成代碼內import。一方面減小加載各種<script>資源的時間,import資源都安裝在服務器上,就只須要加載一個文件就ok了;一方面減小cdn不肯定的因素。

曾經的資源加載方式:

<script src="https://cdn.bootcss.com/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.production.min.js"></script> -->
<script src="https://cdn.bootcss.com/react-router/5.0.1/react-router.min.js"></script>
<script src="https://cdn.bootcss.com/react-router-dom/5.0.1/react-router-dom.min.js"></script>
<script src="http://www.dogcatpig.top/js_rely/babel_min_6.26.0.js"></script>

上面babel不須要import,安裝預設@babel/preset-react、新建配置文件babel.config.json後、用命令npx babel -w 原始文件地址/原始文件名 --out-file 輸出文件地址/輸出文件名輸出翻譯後文件。

可是,其它的資源雖然import/export已是javascript語言標準了,但用起來仍是不行。因此須要webpackwebpack不只能處理import/export & require/export,還能將各類資源打包到一個js文件中,極大的減小網站加載時間。親測若是沒緩存,至少減小一半時間,有緩存2毫秒左右。用法也很簡單,安裝你想要的loaders & plugins,新建配置文件webpack.config.js,用命令npx webpack輸出。

總結流程.png

😊文中配置文件均放置在package.json同目錄😊

相關文章
相關標籤/搜索