Bagaimana cara memasukkan skrip yang terletak di dalam folder node_modules?


275

Saya punya pertanyaan tentang praktik terbaik untuk node_modulesdimasukkan ke situs web HTML.

Bayangkan saya memiliki Bootstrap di dalam node_modulesfolder saya . Sekarang untuk versi produksi situs web, bagaimana saya akan memasukkan skrip Bootstrap dan file CSS yang terletak di dalam node_modulesfolder? Apakah masuk akal untuk meninggalkan Bootstrap di dalam folder itu dan melakukan sesuatu seperti yang berikut ini?

<script src="./node_modules/bootstrap/dist/bootstrap.min.js"></script>

Atau apakah saya harus menambahkan aturan ke file teguk saya yang kemudian menyalin file-file itu ke folder dist saya? Atau apakah lebih baik membiarkan tegukan entah bagaimana menghapus sepenuhnya bootstrap lokal dari file HTML saya dan menggantinya dengan versi CDN?


2
topik terkait stackoverflow.com/questions/24397379/… . SO di sini adalah questino @Palak Bhansali Dengan anggapan orang hanya perlu, apakah itu membenarkan penerapan bower untuk tujuan tunggal ini misalnya katakanlah aplikasi ekspres gulp isntalling bootstrap langsung dari npm, memerlukan akses ke file sekarang dalam tegukan, yang ada di node_modules. Apakah ini membenarkan satu kasus penggunaan untuk membutuhkan bower sekarang untuk tujuan tunggal ini? Itulah masalah yang saya hadapi. Saya sudah menggunakan komposer, npm, tegukan, mendengus, tidak ingin bower secara pribadi, dan tidak ingin mendengus pada aplikasi ini juga.
mengacaukan

Pertanyaan luar biasa yang membutuhkan solusi intuitif!
Sydwell

Jawaban:


297

Biasanya, Anda tidak ingin mengekspos salah satu jalur internal Anda untuk bagaimana server Anda disusun ke dunia luar. Apa yang Anda dapat adalah membuat /scriptsrute statis di server Anda yang mengambil file dari direktori apa pun yang mereka kebetulan tinggal di. Jadi, jika file Anda di "./node_modules/bootstrap/dist/". Kemudian, tag skrip di halaman Anda terlihat seperti ini:

<script src="/scripts/bootstrap.min.js"></script>

Jika Anda menggunakan express dengan nodejs, rute statis semudah ini:

app.use('/scripts', express.static(__dirname + '/node_modules/bootstrap/dist/'));

Kemudian, permintaan browser apa pun dari /scripts/xxx.jssecara otomatis akan diambil dari distdirektori Anda di __dirname + /node_modules/bootstrap/dist/xxx.js.

Catatan: Versi NPM yang lebih baru menempatkan lebih banyak hal di level atas, tidak bersarang terlalu dalam sehingga jika Anda menggunakan versi NPM yang lebih baru, maka nama jalur akan berbeda dari yang ditunjukkan dalam pertanyaan OP dan dalam jawaban saat ini. Tapi, konsepnya masih sama. Anda mencari tahu di mana file-file secara fisik terletak di drive server Anda dan Anda membuat app.use()dengan express.static()untuk membuat pseudo-path ke file-file itu sehingga Anda tidak mengekspos organisasi sistem file server yang sebenarnya kepada klien.


Jika Anda tidak ingin membuat rute statis seperti ini, maka Anda mungkin lebih baik hanya menyalin skrip publik ke jalur yang diperlakukan oleh server web Anda sebagai /scriptsatau sebutan tingkat atas apa pun yang ingin Anda gunakan. Biasanya, Anda dapat menjadikan salinan ini sebagai bagian dari proses build / deployment Anda.


Jika Anda ingin membuat hanya satu file tertentu publik dalam direktori dan tidak semua yang ditemukan dalam direktori itu, maka Anda dapat secara manual membuat rute individual untuk setiap file daripada menggunakan express.static()seperti:

<script src="/bootstrap.min.js"></script>

Dan kode untuk membuat rute untuk itu

app.get('/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});

Atau, jika Anda masih ingin menggambarkan rute untuk skrip /scripts, Anda dapat melakukan ini:

<script src="/scripts/bootstrap.min.js"></script>

Dan kode untuk membuat rute untuk itu

app.get('/scripts/bootstrap.min.js', function(req, res) {
    res.sendFile(__dirname + '/node_modules/bootstrap/dist/bootstrap.min.js');
});

2
Apakah saya perlu menyalinnya secara manual atau ada cara Grunt untuk melakukannya? Saya pikir entah bagaimana yang terbaik adalah dengan sepenuhnya menyalin folder bootstrap /scriptskarena dengan cara itu setiap dependensi di dalam modul akan dipertahankan.
Chris

@phpheini - mungkin ini akan membantu: stackoverflow.com/questions/18966485/… dan ini npmjs.com/package/grunt-copy
jfriend00

1
@RobertOschler - Tidak, itu tidak memeriksa dups. express.static()mengirimkan kecocokan pertama yang ditemukannya. Karena setiap express.static()pernyataan hanya membuat satu jalur pencocokan yang mungkin, tidak boleh ada duplikat dari satu express.static()pernyataan. Jika Anda memiliki beberapa express.static()pernyataan yang masing-masing dapat memiliki kecocokan, maka yang pertama dalam kode Anda adalah yang kecocokannya akan digunakan. Juga, Anda seharusnya tidak memiliki banyak file dengan nama dan jalur relatif yang sama yang dapat dijangkau oleh express.static()pernyataan. Praktik terbaik adalah tidak melakukan itu.
jfriend00

1
@RobertOschler - Anda harus sangat, sangat berhati-hati tentang apa yang Anda berikan akses yang tidak diatur. Secara umum, Anda hanya harus menunjuk express.static()pada direktori yang HANYA berisi file publik (termasuk sub-direktori). Jadi, saya tidak bisa membayangkan proyek di mana ada banyak distdirektori yang diterbitkan. Bagi saya itu sangat tidak biasa. Mungkin Anda ingin membuat rute spesifik ke file tertentu atau ke 2-3 file. Dalam hal ini, Anda bertanggung jawab untuk melambangkan file-file itu. Lagipula tidak ada gunanya bagimu untuk memiliki empat script.jsfile.
jfriend00

1
@RobertOschler - Jika Anda tidak membuat jalur unik diperlukan di depan mereka untuk mencocokkan, tidak ada cara bagi kode apa pun untuk mengetahui mana yang akan ditayangkan ketika /script.jsdiminta oleh browser. Jadi, jawaban abstraknya adalah Anda tidak boleh membiarkan situasi duplikat nama file ada karena itu bukan masalah yang dapat dipecahkan kecuali Anda memerlukan awalan unik untuk setiap direktori file. Kemudian, duplikat nama akar tidak menjadi masalah. Untuk jawaban yang lebih spesifik dengan rekomendasi terperinci, Anda perlu memposting pertanyaan Anda sendiri dengan detail yang tepat.
jfriend00

18

Saya akan menggunakan modul path npm dan kemudian melakukan sesuatu seperti ini:

var path = require('path');
app.use('/scripts', express.static(path.join(__dirname, 'node_modules/bootstrap/dist')));

PENTING: kami menggunakan path.join untuk membuat lintasan bergabung menggunakan cara agnostik sistem, yaitu pada windows dan unix kami memiliki pemisah jalur yang berbeda (/ dan)


tandai duplikat seperti di atas, path.join hanyalah ukuran tambahan, tetapi solusi yang masih sama dengan menambahkan path statis ke dir node_modules.
mengacaukan

2
"path.join hanyalah ukuran tambahan, tetapi masih solusi yang sama" bukan solusi yang sama. Sebenarnya itu menggunakan sistem khusus bergabung (ingatlah / dan \ pemisah di windows dan unix)
Alexander Egorov

4
OK, saya mengerti maksud Anda, ya itu selalu baik untuk memiliki sistem agnostik, saya tidak tahu apa itu. Terima kasih telah menunjukkannya. Lebih baik menambahkannya ke kalimat dalam jawaban Anda, alih-alih hanya memberikan kode :-), mis. Jelaskan kode Anda.
blamb

10

Seperti yang disebutkan oleh jfriend00 Anda tidak boleh mengekspos struktur server Anda. Anda dapat menyalin file ketergantungan proyek Anda ke sesuatu seperti public/scripts. Anda dapat melakukan ini dengan sangat mudah dengan dep-linker seperti ini:

var DepLinker = require('dep-linker');
DepLinker.copyDependenciesTo('./public/scripts')
// Done

1
Script srckemudian akan menjadi seperti /scripts/[package-name]/dist/file.min.js.
Jacob Ford

7

Jika Anda menginginkan solusi yang cepat dan mudah (dan Anda telah menelannya).

Dalam saya, gulpfile.jssaya menjalankan tugas copy paste sederhana yang menempatkan file apa pun yang saya butuhkan ke ./public/modules/direktori.

gulp.task('modules', function() {
    sources = [
      './node_modules/prismjs/prism.js',
      './node_modules/prismjs/themes/prism-dark.css',
    ]
    gulp.src( sources ).pipe(gulp.dest('./public/modules/'));
});

gulp.task('copy-modules', ['modules']);

Kelemahan dari ini adalah tidak otomatis. Namun, jika yang Anda butuhkan hanyalah beberapa skrip dan gaya yang disalin (dan disimpan dalam daftar), ini harusnya berhasil.


Orang bisa menambahkan ini di package.json dalam skrip 'scripts': {'install':'yarn gulp copy-modules'}, dengan asumsi benang adalah manajer paket dan tegukan diinstal dalam paket.
Todd

6

Direktori 'node_modules' mungkin tidak ada di direktori saat ini, jadi Anda harus menyelesaikan jalur secara dinamis.

var bootstrap_dir = require.resolve('bootstrap')
                           .match(/.*\/node_modules\/[^/]+\//)[0];
app.use('/scripts', express.static(bootstrap_dir + 'dist/'));

+1, meskipun saya tidak berpikir ini akan berhasil dalam semua kasus - egan npm linked module yang tidak ada dalam subfolder node_modules
Alasdair McLeay

3

Saya ingin memperbarui pertanyaan ini dengan solusi yang lebih mudah. Buat tautan simbolis ke node_modules.

Cara termudah untuk memberikan akses publik ke node_modules adalah dengan membuat tautan simbolis yang menunjuk ke node_modules Anda dari dalam direktori publik Anda. Symlink akan membuatnya seolah-olah file ada di mana pun tautan dibuat.

Misalnya, jika server simpul memiliki kode untuk menyajikan file statis

app.use(serveStatic(path.join(__dirname, 'dist')));

dan __dirname merujuk ke / path / ke / app sehingga file statis Anda dilayani dari / path / ke / app / dist

dan node_modules ada di / path / ke / app / node_modules, lalu buat symlink seperti ini di mac / linux:

ln -s /path/to/app/node_modules /path/to/app/dist/node_modules

atau seperti ini di windows:

mklink /path/to/app/node_modules /path/to/app/dist/node_modules

Sekarang dapatkan permintaan untuk:

node_modules/some/path 

akan menerima respons dengan file di

/path/to/app/dist/node_modules/some/path 

yang benar-benar file di

/path/to/app/node_modules/some/path

Jika direktori Anda di / path / ke / app / dist bukanlah lokasi yang aman, mungkin karena gangguan dari proses build dengan tegukan atau gerutuan, maka Anda bisa menambahkan direktori terpisah untuk tautan dan menambahkan panggilan serveStatic baru seperti:

ln -s /path/to/app/node_modules /path/to/app/newDirectoryName/node_modules

dan di simpul tambahkan:

app.use(serveStatic(path.join(__dirname, 'newDirectoryName')));

1
Tetapi kemudian Anda telah memindahkan aplikasi Anda ke jalur yang berbeda dan symlink tidak valid. Atau Anda ingin menjalankan aplikasi di mesin lain (test / prod), Anda harus membuatnya lagi. Kontributor apa pun untuk aplikasi Anda harus melakukan hal yang sama. Ini menambahkan beberapa pemeliharaan atas solusi di atas.
mati.o

@ mati.o Bagaimana dengan tautan simbolis relatif? Saya suka solusi ini, tetapi hanya dengan symlink relatif.
Lukáš Bednařík

3

Saya tidak menemukan solusi bersih (saya tidak ingin mengekspos sumber semua node_modules saya) jadi saya hanya menulis skrip Powershell untuk menyalinnya:

$deps = "leaflet", "leaflet-search", "material-components-web"

foreach ($dep in $deps) {
    Copy-Item "node_modules/$dep/dist" "static/$dep" -Recurse
}

1

Saya melakukan perubahan di bawah untuk AUTO-INCLUDE file dalam indeks html. Sehingga ketika Anda menambahkan file dalam folder itu akan secara otomatis diambil dari folder, tanpa Anda harus memasukkan file dalam index.html

//// THIS WORKS FOR ME 
///// in app.js or server.js

var app = express();

app.use("/", express.static(__dirname));
var fs = require("fs"),

function getFiles (dir, files_){
    files_ = files_ || [];
    var files = fs.readdirSync(dir);
    for (var i in files){
        var name = dir + '/' + files[i];
        if (fs.statSync(name).isDirectory()){
            getFiles(name, files_);
        } else {
            files_.push(name);
        }
    }
    return files_;
}
//// send the files in js folder as variable/array 
ejs = require('ejs');

res.render('index', {
    'something':'something'...........
    jsfiles: jsfiles,
});

///--------------------------------------------------

///////// in views/index.ejs --- the below code will list the files in index.ejs

<% for(var i=0; i < jsfiles.length; i++) { %>
   <script src="<%= jsfiles[i] %>"></script>
<% } %>

1

Ini yang saya siapkan di expressserver saya :

// app.js
const path = require('path');
const express = require('express');
const expressApp  = express();
const nm_dependencies = ['bootstrap', 'jquery', 'popper.js']; // keep adding required node_modules to this array.
nm_dependencies.forEach(dep => {
  expressApp.use(`/${dep}`, express.static(path.resolve(`node_modules/${dep}`)));
});

<!-- somewhere inside head tag -->
<link rel="stylesheet" href="bootstrap/dist/css/bootstrap.css" />

<!-- somewhere near ending body tag -->
<script src="jquery/dist/jquery.js" charset="utf-8"></script>
<script src="popper.js/dist/popper.js" charset="utf-8"></script>
<script src="bootstrap/dist/js/bootstrap.js" charset="utf-8"></script>

Semoga berhasil...

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.