Migrating RequireJS/AMD with Plugins to Webpack - requirejs

I'm working on migrating a large RequireJS application to Webpack. The basic build with Webpack seems to work fine -- I've moved "paths" definitions to "alias" and I've setup loaders for my content and shims, like jQuery.
However, there's a remaining issue I'm not sure how to resolve. Basically the RequireJS app uses the "text-plugin" to include HTML templates, and Webpack is throwing "Module not found" errors for the HTML templates.
An example AMD module I want to bundle looks something like this:
AMD Module with Text Plugin
define([
'security',
'modals',
'text!../templates/contact_info.html'
], function(security, modals, contactInfoTemplate) {
return {
foo: function() { return "bar"; }
};
});
I thought I could use the raw-loader to load the template files. I aliased 'text' to be the 'raw-loader':
text: {
test: /\.html$/,
loader: "raw-loader"
},
However, I'm seeing the following error for all of my templates that are required like above:
Module not found: Error: Can't resolve 'text'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'text-loader' instead of 'text'.
I tried replacing 'text!...' with 'text-loader!...', and I then see this error complaining that it can't load/find the HTML module!
Module not found: Error: Can't resolve '../templates/contact_info.html'
webpack.config.js, version 3.9.1
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
let basePath = path.join(__dirname, '/');
module.exports = {
entry: {
'main': basePath + 'js/main.js',
},
context: __dirname,
output: {
path: __dirname + '/build',
filename: '[name].min.js',
libraryTarget: 'amd',
umdNamedDefine: true
},
module: {
rules: [
{
test: /(\.js)$/,
exclude: /(node_modules)/,
use: {
// babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
plugins: []
}
}
},
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
{ test: /\.jpg$/, use: [ "file-loader" ] },
{ test: /\.png$/, use: [ "url-loader?mimetype=image/png" ] },
{
test: /\.(html)$/,
use: {
loader: 'raw-loader',
options: {
minimize: true
}
}
}
]
},
resolve: {
modules: [
'js/**/*.js',
'node_modules',
path.resolve('./js')
],
extensions: ['.js'], // File types,
alias: {
text: {
test: /\.html$/,
loader: "raw-loader"
},
bridge: 'libs/bridge',
cache: 'libs/cache',
cards: 'libs/cards',
moment: 'libs/moment',
underscore: 'libs/underscore',
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
filename: 'index.html',
template: '../index.html'
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
Anyone know how to get Webpack to play nicely with the RequireJS Text plugin?
Thanks!

Maybe try installing text-loader?
In order for something like 'text!../templates/contact_info.html' to "load" properly, since it is not JS, you need to install text-loader to get webpack to understand the syntax text!.
npm install text-loader --save-dev
humm...i just installed text-loaded and it seems we also have to change text! to text-loader!

Related

How to configure Webpack to not pull content of imported Sass files to a source map?

I have a Sass file that imports Bootstrap and Font Awesome.
They has been put on the of the file before my custom CSS class.
Here is the code:
/src/scss/site.scss
#import "~bootstrap/scss/bootstrap";
#import "~font-awesome/scss/font-awesome";
// Custom style sheet here
.my-custom-header{
color:#F00
}
There is a source map after Webpack build but it includes the content of Bootstrap and font awesome.
Here what is look like in Browser:
When I tried to inspect a custom class it point to correct line number of origin source code but incorrect for generated source map because it has content of Bootstrap in the top.
My question is:
Is it possible to configure a output source map to keep the import statement and the content is exact the same as actual source code.
Here what source map I'm expected.
site.css.map
#import "~bootstrap/scss/bootstrap";
#import "~font-awesome/scss/font-awesome";
// Custom style sheet here
.my-custom-header{
color:#F00
}
Here my Webpack configuration:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const siteFile = [__dirname, 'src', 'scss', 'site'];
const outputPath = [__dirname, 'public', 'css'];
module.exports = {
entry: {
site: path.resolve(...siteFile),
},
output: {
path: path.resolve(...outputPath),
},
resolve: {
// https://github.com/webpack/webpack-dev-server/issues/720#issuecomment-268470989
extensions: ['.scss']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader', // Translates CSS into CommonJS modules
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader', // Run post css actions
options: {
plugins: () => {
// post css plugins, can be exported to postcss.config.js
return [
require('precss'),
require('autoprefixer')
];
},
sourceMap: true
}
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader', // Compiles Sass to CSS, using node-sass by default
options: {
sourceMap: true
}
}
],
exclude: /node_modules/
},
{
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff2?)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '.' //relative to output
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: './[name].css' // relative to output
}),
],
devServer: {
contentBase: path.join(__dirname, 'public'),
compress: false,
port: 8080,
}
};
Here is a link to a repository of the example code.
codesanook-examples-webpack
Thank you.
Have you tried SourceMapDevToolPlugin?
https://webpack.js.org/plugins/source-map-dev-tool-plugin/
You might need to create a vendor bundle for node modules stuff then you can ignore it from sourcemap.

Unable to load sp-loader for spfx solution with webpack

my typescript file includes the following import:
import { SPComponentLoader } from '#microsoft/sp-loader';
But I get a lot of errors when building with webpack
npx webpack --config webpack.config.js
Here are some of the errors:
ERROR in
./node_modules/#microsoft/sp-loader/lib/requirejs/RequireJsLoader.js
Module not found: Error: Can't resolve './test/RequireJsMock' in
'C:\users\agaskell\source\repos\spfxBanner\node_modules#microsoft\sp-loader\lib\requirejs'
# ./node_modules/#microsoft/sp-loader/lib/requirejs/RequireJsLoader.js
258:14-45 #
./node_modules/#microsoft/sp-loader/lib/requirejs/SPRequireJsComponentLoader.js
# ./node_modules/#microsoft/sp-loader/lib/starter/SPStarter.js #
./node_modules/#microsoft/sp-loader/lib/index.js #
./Classic/client/bootHeader.ts # multi #babel/polyfill
./Classic/client/bootHeader.ts
ERROR in
./node_modules/#microsoft/sp-loader/lib/systemjs/SystemJsLoader.js
Module not found: Error: Can't resolve './test/SystemJsMock' in
'C:\users\agaskell\source\repos\spfxBanner\node_modules#microsoft\sp-loader\lib\systemjs'
I am trying to build my ts file into js for classic SharePoint sites and I normally use gulp for modern pages, but for classic I am using a separate bootloader.ts file and webpack.
Can anyone help?
Here is the webpack.config.js file:
const path = require("path");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: "development",
entry: ['#babel/polyfill',
path.resolve(__dirname, './Classic/client/bootHeader.ts')],
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/
},
{
test: /\.(s*)css$/,
use: [
// fallback to style-loader in development
process.env.NODE_ENV !== "production"
? "style-loader"
: MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
},
{
test: /\.(png|jp(e*)g|svg)$/,
use: [
{
loader: "url-loader",
options: {
limit: 15000, // Convert images < 8kb to base64 strings
name: "images/[hash]-[name].[ext]"
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
output: {
filename: "classicBundleAG.js",
path: path.resolve(__dirname, "Classic"),
libraryTarget: "umd"
}
};
I ended up using a workaround for this. I gave up on SPComponentLoader to load my bootstrap and instead installed bootstrap modules locally and then referenced them from my custom sass.
My thoughts are that gulp with yeoman normally handles the SPComponentLoader dependencies, but this time I am using a custom webpack and I did not want to deal with every missing dependency manually.

Migrating from Grunt+Bower to Webpack

I am trying to migrate away from Bower+Grunt to Webpack (and eventually to YARN instead of Bower).
However, any documentation I have come across for WebPack3 doesn't even talk about handling bower components.
WebPack 2 used a plugin for Bower, however the same isn't supported for WebPack 3.
Here's my WebPack config:
const webpack = require('webpack');
const path = require('path');
const frontEndConfig = {
entry: {
client: './client/app/app.js'
},
output: {
path: path.resolve(__dirname, 'dist/client/'),
filename: '[name].app.js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
]
},
resolve: {
modules: ['bower_components'],
descriptionFiles: ['bower.json'],
}
};
const backEndConfig = {
entry: {
client: './server/app.js'
},
output: {
path: path.resolve(__dirname, 'dist/server/'),
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
],
rules: [{
exclude: ['node_modules']
}]
},
resolve: {
modules: ['node_modules'],
descriptionFiles: ['package.json'],
}
};
module.exports = [
frontEndConfig,
backEndConfig
];;
The whole idea is to first run using webpack and then move completely to YARN.
They say plugins have been stopped for WebPack3, so what's the workaround for this?

Publish multiple Vuejs components in one project to npm using webpack

Im trying to publish a project to npm that contains two or more Vue components so i can import, register and use both components like this:
import Component1 from 'npm-package'
import Component2 from 'npm-package'
this is my webpack file:
const webpack = require('webpack');
const merge = require('webpack-merge');
const path = require('path');
var config = {
output: {
path: path.resolve(__dirname + '/dist/'),
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: __dirname,
exclude: /node_modules/
},
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.css$/,
loader: 'style!less!css'
}
]
},
externals: {
moment: 'moment'
},
plugins: [
new webpack.optimize.UglifyJsPlugin( {
minimize : true,
sourceMap : false,
mangle: true,
compress: {
warnings: false
}
} )
]
};
module.exports = [
merge(config, {
entry: path.resolve(__dirname + '/src/plugin.js'),
output: {
filename: 'vue-project.min.js',
libraryTarget: 'window',
library: 'VueProject',
}
}),
merge(config, {
entry: path.resolve(__dirname + '/src/index.js'),
output: {
filename: 'vue-project.js',
libraryTarget: 'umd',
library: 'vue-project',
umdNamedDefine: true
},
resolve: {
extensions: ['', '.js', '.vue'],
alias: {
'src': path.resolve(__dirname, '../src'),
'components': path.resolve(__dirname, '../src/components')
}
}
})
];
and this is the index.js file i'm using as the entry point for the build process
import Component1 from './components/folder1/Component1.vue'
import Component1 from './components/folder2/Component2.vue'
export default {
components: {
Component1,
Component2
}
}
The build process using npm run build works fine and i can publish the project to npm and install it using npm install. Importing and using it works fine to, but when i run my project i get the error:
failed to mount component: template or render function not defined.
All other posts o found regarding this error did not solve my problem, as none of them tried to export multiple components.
Both components work completely as intended when im publishing them in two different projects.
What am i missing here? Thanks in advance!
You don't need to export using the components property, you simply need to do:
export {
Component1,
Component2
}
You would then do:
import {Component1} from 'npm-package';
import {Component2} from 'npm-package';
or
import {Component1, Component2} from 'npm-package';
see: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export

Webpack not including ProvidePlugins

I have a small trial web application that I'm working on that uses the vue webpack template (https://github.com/vuejs-templates/webpack). I'm pretty new to webpack so I was assuming that I could add in to plugins a new webpack.ProvidePlugin and it would be available globally but when I do a npm run dev I get the following error:
/var/www/public/leadsStatsDashboard/liveleadstats/src/components/Hello.vue
18:17 error 'd3' is not defined no-undef
Which sounds like to me that it can't find the d3 reference. I'm no sure if there's some configuration I skipped over or what but any help would be appreciated. Here is the source for my files
Webpack.dev.conf.js:
var path = require('path')
var config = require('../config')
var utils = require('./utils')
var webpack = require('webpack')
var projectRoot = path.resolve(__dirname, '../')
module.exports = {
plugins: [
new webpack.ProvidePlugin({
d3: 'd3',
crossfilter: 'crossfilter',
dc: 'dc'
})
],
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
publicPath: config.build.assetsPublicPath,
filename: '[name].js'
},
resolve: {
extensions: ['', '.js', '.vue'],
fallback: [path.join(__dirname, '../node_modules')],
alias: {
'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'),
'components': path.resolve(__dirname, '../src/components'),
'd3': path.resolve(__dirname, '../bower_components/d3/d3.min.js'),
'crossfilter': path.resolve(__dirname, '../bower_components/crossfilter/crossfilter.min.js'),
'dc': path.resolve(__dirname, '../bower_components/dcjs/dc.js')
}
},
resolveLoader: {
fallback: [path.join(__dirname, '../node_modules')]
},
module: {
preLoaders: [
{
test: /\.vue$/,
loader: 'eslint',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.js$/,
loader: 'eslint',
include: projectRoot,
exclude: /node_modules/
}
],
loaders: [
{
test: /\.vue$/,
loader: 'vue'
},
{
test: /\.js$/,
loader: 'babel',
include: projectRoot,
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.html$/,
loader: 'vue-html'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url',
query: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
eslint: {
formatter: require('eslint-friendly-formatter')
},
vue: {
loaders: utils.cssLoaders()
}
}
Hello.vue
<template>
<div id="pieChartContainer">
</div>
</template>
<script>
export default {
data () {
return {
// note: changing this line won't causes changes
// with hot-reload because the reloaded component
// preserves its current state and we are modifying
// its initial state.
msg: 'Hello World! This is a test'
}
},
ready () {
console.log(d3.version)
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1 {
color: #42b983;
}
</style>
Your error isn't emitted from webpack, but from eslint.
I think the webpack part works as it should, in fact!
no-undef complains that you are using the global d3 without importing or defining it somewhere.
The good news is, that's easy to fix. Use any of the following three possibilities:
Just add the following block to your .eslintrc.js:
"globals": {
"d3": true
}
...or use eslint comments within the file that requires d3 implicitly (but that doesn't make much sense as you made it available globally and you would need to do this in every file you wish to use the global var):
/* eslint-disable no-undef */
...or you could relax the eslint rule in your .eslintrc.js config:
'rules': {
// all other rules...
'no-undef': 0
}
Additional links:
Direct link to the template's eslintrc file
The eslint 'standard' file the template extends
Further reading on eslint's no-undef rule

Resources